Annotated / Case study2026 / live

RentIt

Earn from what you own. Rent what you need for the moment.

ContributionSole developer

An item rental platform where owners list things they are not using and renters request temporary access, with bookings and messaging.

01

The premise

RentIt connects people who have items they are not using with people who need them temporarily. Owners can list those items with the aim of earning extra money; renters can request access for the time they need instead of buying. The implementation brings listings, date selection, booking requests and booking-linked conversations into one flow. This case study follows that exchange, including profile requirements, changing availability and the owner controls that keep a listing manageable after it has been published.

02

Follow a booking

Follow the source-backed journey through the supplied screens. Each step separates visible interface evidence from behavior established in code. The complete reading path below works without JavaScript.

Jump to a figure
  1. 01

    Browse

    Search and filter listings before choosing an item.

    RentIt browse results with location and price filters, sort control and three item cards.
    Browse results with location and price filters and three available items. The laptop card has no visible photo in this capture.

    Source: rentit:src/shared/lib/constants.js

  2. 02

    Inspect the listing

    Read the listing details before choosing a rental window.

    RentIt PS5 listing description and host information beside an owner Manage Availability calendar.
    Listing detail in the owner's availability view. The gallery and renter date-selection controls are not in this capture.

    Source: rentit:src/features/bookings/components/AvailabilityCalendar.jsx

  3. 03

    Request a booking

    The booking hook checks profile requirements and reads availability again before inserting a pending request.

    RentIt profile form with photo controls, full name, location and bio fields.
    Profile fields and photo controls. This capture does not show a save result or the profile-completion prompt.
    RentIt Lending booking list with status filters and pending rows offering Approve and Decline.
    Owner-side booking management with Lending and Renting controls, status filters, and pending requests. It does not show renter submission or an approval outcome.

    Source: rentit:src/features/bookings/hooks/useCreateBooking.js

  4. 04

    Continue the conversation

    Message history belongs to the booking, keeping the conversation in context.

    RentIt booking conversation with PS5 listing context, incoming and outgoing greetings and a message composer.
    Booking-specific conversation with greetings and a composer. Broken image placeholders remain visible. A still does not establish real-time delivery.

    Source: rentit:src/features/messages/hooks/useMessages.js

  5. 05

    Manage the listing

    Owners can edit, hide and restore an existing listing through the listing hook.

    RentIt My Listings view with an active PS5 listing and Edit, Remove from Browse and Delete controls.
    Existing-listing management with Edit, Remove from Browse and Delete controls. Completed mutations and the restore state were not captured.
    Read the listing-update decision

    Source: rentit:src/features/listings/hooks/useListing.js

Creating and overseeing listings

Supporting owner views, separate from the renter's request flow.

RentIt New Listing form with title, description, category and daily-price fields.
Upper portion of the New Listing form. An empty creation form does not show submission or editing an existing listing.
RentIt owner dashboard with listing, booking and request summaries and recent bookings.
Owner dashboard with recent bookings and a notification opt-in prompt. Captured counts are interface state, not portfolio outcome metrics. Earnings are labeled Coming soon.

Permission map

Source behavior and migration intent, not a certification of the deployed database.

Anonymous
The listing-detail route is public. Booking submission requires sign-in.rentit:src/App.jsx; src/features/bookings/hooks/useCreateBooking.js
Renter
The booking hook checks profile requirements and inserts a pending request with the current user as renter. The renter booking view filters by user id.rentit:src/features/bookings/hooks/useCreateBooking.js; useBookings.js
Owner
The owner view queries bookings for owned listing ids. The listing UPDATE migration checks ownership of both the existing and resulting row.rentit:src/features/bookings/hooks/useBookings.js; supabase/migrations/20260802000000_listings_update_policy.sql
Participants
The message INSERT migration checks sender identity, completed profile and participation as renter or listing owner. Applied production policies remain unverified.rentit:supabase/migrations/20260726010000_require_complete_profile.sql; 20260730000000_profile_completion_location.sql
03

Decisions

Decision 01security / kept

Replace unknown UPDATE policies with one owner policy

Original listing policies were manually created and their names were not versioned. The migration records rejected owner updates.

Options
  • Leave existing policies in place.
  • Add another policy alongside them.
  • Discover and replace all listing UPDATE policies.
Choice
Iterate pg_policies, drop listing UPDATE policies and create one owner-only policy.
Trade-off
The script also removes any other listing UPDATE rule and contains no rollback. The owner confirmed this cost during case-study review.
Evidence
  • Policy replacement scriptrentit@f07791d:supabase/migrations/20260802000000_listings_update_policy.sql
  • Policy fixrentit commit c9a206e
  • Historical decision draftdocs/seed-promotion-drafts.md, RentIt seed 2
  • Owner confirmed alternatives and trade-offsdocs/rentit-case-study.md, Decision review confirmation, 2026-10-05
Decision 02architecture / kept

Deliver notification events through database triggers

The migration records that the dashboard Database Webhooks UI was unavailable on this project.

Options
  • Use the unavailable dashboard Webhooks UI.
  • Use triggers and pg_net with Vault lookups.
Choice
Triggers post booking and message events to the Edge Function.
Trade-off
Two Vault reads per invocation; missing configuration skips delivery while the insert succeeds. The owner confirmed these costs in docs/seed-promotion-drafts.md. Production delivery is unverified.
Evidence
  • Trigger implementation and missing-configuration pathsrentit@f07791d:supabase/migrations/20260804000000_webpush_pg_net_triggers.sql
  • Trigger delivery implementationrentit commit e2a1aaf
  • Owner-confirmed costsdocs/seed-promotion-drafts.md, RentIt seed 7
  • Owner confirmed alternatives and trade-offsdocs/rentit-case-study.md, Decision review confirmation, 2026-10-05
Decision 03security / kept

Update existing listings instead of upserting

Three listing mutation paths used upsert, omitting owner_id required by the INSERT policy.

Options
  • Keep the previous upsert path.
  • Use UPDATE filtered by listing id.
Choice
Use UPDATE for edits, hiding and restoring existing listings.
Trade-off
No lost creation capability on this path, according to owner confirmation recorded in docs/seed-promotion-drafts.md: it only changes an existing listing.
Evidence
  • Listing mutation implementationrentit@f07791d:src/features/listings/hooks/useListing.js
  • Mutation fixrentit commit 4f7fb62
  • Recorded owner cost confirmationdocs/seed-promotion-drafts.md, RentIt seed 1
  • Owner confirmed alternatives and trade-offsdocs/rentit-case-study.md, Decision review confirmation, 2026-10-05
04

The tools

React
Reusable components and hooks for loading, error and interaction states across listings, bookings and conversations.
Supabase
Authentication, records, storage and real-time messaging in one backend for an independent build.
Zod
Explicit create and edit form rules expressed in validation schemas before submitting listing data.
Vite
Development and production build tooling for the React application.
Tailwind CSS
Utility classes for feature styling and responsive layouts across listings, bookings and the dashboard.
05

Problems and fixes

An existing listing could still hit an INSERT policy

Editing, hiding and restoring a listing used upsert. The payload omitted owner_id, which the INSERT policy expected even when the intended operation was a change to an existing row. The fix used UPDATE filtered by listing id across all three paths. The hook then selects the changed row and surfaces an error when that operation fails.

Calendar availability could become stale before submission

A renter could select dates before another approved booking changed availability. The booking hook fetches blocked ranges again before inserting and rejects an overlap with a message asking for different dates. It also stops when the availability query fails. That catches changes visible at the second read; the read and insert remain separate operations, so this is not an atomic concurrency guarantee.

A same-day selection produced a zero-night booking

The previous day-difference calculation could return zero for a same-day range. The implementation clamps the calendar calculation to at least one night and adds guards against fewer than one night and a non-positive total. That removes the zero-price path in the inspected code. Why clamping was preferred to rejecting the selection, and whether the wording matches the rental model, remain unverified.

06

What I would change

The next improvement would be to make the database setup reproducible and verify booking conflicts at the write boundary. The repository does not contain the original creation migrations for several core tables, and the availability check happens before a separate insert. I would also revisit how a same-day selection is explained: clamping it to one night prevents a zero total, but the product should make that rule clear. These are my next priorities, not changes completed in this build.