Skip to content

F-030: Report / Flag Listing

Status: Done · Priority: P2 · Updated: Mar 7, 2026

Summary

Scraped listings can be outdated, duplicate, or spam. Currently there's no way for users to report issues. Every competitor has this. Essential for platform trust and data quality.

Requirements

  • [x] "Report this listing" button on listing detail page
  • [x] Reason picker: already rented, wrong info, spam/scam, duplicate, other
  • [x] Optional comment field for details
  • [x] New listing_reports DB table
  • [x] API endpoint to submit reports
  • [x] Rate limiting (max reports per user/IP per hour)
  • [x] Admin view to review reports
  • [x] Bilingual (FR/EN)
  • [ ] Auto-archive after N reports threshold (deferred — manual review only for now)

Design

DB Schema

sql
listing_reports (
  id uuid PK,
  listing_id uuid FK listings NOT NULL,
  user_id uuid FK users NULL,        -- null for anonymous reports
  reason enum NOT NULL,               -- already_rented, wrong_info, spam, duplicate, other
  comment text,
  reporter_ip text,
  status enum DEFAULT 'pending',      -- pending, reviewed, dismissed
  admin_notes text,
  metadata jsonb,                     -- userAgent, deviceType, browser, os, locale
  created_at timestamptz DEFAULT now(),
  resolved_at timestamptz
)

API Endpoints

MethodPathAuthDescription
POST/listings/:id/reportOptionalSubmit a report
GET/api/reportsAdminList reports (admin dashboard)
PATCH/api/reports/:idAdminUpdate report status

Frontend

  • Flag icon button on listing detail page (near share button)
  • Dialog with reason radio buttons + optional comment textarea
  • Toast confirmation after submit
  • No login required to report (but capture user_id if logged in)

Discussion Notes

Mar 7, 2026 — Created. XS-S effort. Need DB migration, one API endpoint, one dialog component.

Implementation Notes

Mar 7, 2026 — Implemented end-to-end:

  • DB: listing_reports table with report_reason and report_status enums, metadata JSONB
  • API: POST /listings/:id/report — public, optional auth (try/catch JWT), rate limited (5/IP/hour), captures device metadata via ua-parser-js
  • Admin API: GET /api/reports (paginated, filterable by status), PATCH /api/reports/:id (update status + adminNotes, auto-set resolvedAt)
  • Admin UI: Reports page with reason/status badges, review/dismiss/reopen actions, reporter info display
  • Frontend: ReportForm dialog component with radio buttons for reason, optional comment textarea, integrated next to Share button on listing detail
  • Translations: report namespace in both EN and FR
  • No auto-archive — all reports reviewed manually by admin