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
01
Browse
Search and filter listings before choosing an item.
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
02
Inspect the listing
Read the listing details before choosing a rental window.
Listing detail in the owner's availability view. The gallery and renter date-selection controls are not in this capture.
The booking hook checks profile requirements and reads availability again before inserting a pending request.
Profile fields and photo controls. This capture does not show a save result or the profile-completion prompt.Owner-side booking management with Lending and Renting controls, status filters, and pending requests. It does not show renter submission or an approval outcome.
Owners can edit, hide and restore an existing listing through the listing hook.
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
Supporting owner views, separate from the renter's request flow.
Upper portion of the New Listing form. An empty creation form does not show submission or editing an existing listing.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.
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
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.
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.