Appearance
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_reportsDB 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
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /listings/:id/report | Optional | Submit a report |
| GET | /api/reports | Admin | List reports (admin dashboard) |
| PATCH | /api/reports/:id | Admin | Update 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_reportstable withreport_reasonandreport_statusenums, 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:
ReportFormdialog component with radio buttons for reason, optional comment textarea, integrated next to Share button on listing detail - Translations:
reportnamespace in both EN and FR - No auto-archive — all reports reviewed manually by admin