Bangladesh's smartest room rental platform. Find verified, affordable rooms with AI-powered recommendations, real-time chat, secure payments, roommate matching, and fraud detection.
- Product Overview
- Changelog — Phase 18.3 · 18.2 · 18.1 · 17
- What's New in v2.0
- Delivery Roadmap
- Features
- Tech Stack
- Architecture
- Project Structure
- Quality Engineering
- Getting Started
- API Endpoints
- Documentation
- Security
- Passkeys / WebAuthn
- Progressive Web App
- Demo Users
- Screenshots
- Team Workflow
- Developer
- License
| Problem | Finding a trustworthy room in Dhaka is hard — listings are scattered, landlords are hard to verify, and scams are common. |
| Solution | One verified marketplace: AI-scanned listings, real-time landlord chat, secure gateway payments, roommate matching, and an ML-powered fraud engine that catches bad actors before tenants do. |
| Target users | Tenants (students & young professionals) and landlords in Bangladesh. |
| Differentiators | Fraud-engineered trust layer, AI recommendations & fair-price insight, roommates (a growth hook competitors lack), and a monetized listing-tier system (Free → Featured → Premium). |
One platform, four surfaces — browse smarter, trust the listings, sell faster, run on data:
| Surface | What you see | Screenshot |
|---|---|---|
| 🗺️ Intelligent Map | AI map search ("উত্তরায় ১২ হাজারের মধ্যে furnished room"), metro commute scores, value-score pins, area intelligence & affordability | map-intel-ai-search.png |
| 🔍 AI Smart Search | Bangla/Banglish natural-language search with intent chips + semantic ranking | phase11-ai-search.png |
| 🛡️ Fraud Operations | Auto-scanned listings, risk scores, admin review queue + duplicate-image detection | fraud-admin.png |
| 🧑🤝🧑 Roommate Matching | Compatible flatmates by budget, area & lifestyle | roommates-matching.png |
| 🛡️ Trust & Safety | Two-sided marketplace integrity — tenant KYC + verified-tenant badge, chat safety engine, report/block, photo & review moderation, disputes + deposit protection, admin Trust Center & audit trail | trust-center.png |
| 📱 Reach | SMS OTP phone sign-in for the Bangladesh market, one-tap Share on WhatsApp with an AI listing summary, per-area SEO landing pages + sitemap, Lighthouse gate in CI | phase13-area-page.png |
| 👁️ AI Vision | Photo intelligence — analyze a listing's photos (caption, palette, observations), AI draft title + description from the actual photos, suggested amenity tags (review-then-apply), and AI image search ("upload a photo, find rooms that look like it") with match scores | phase14-vision-panel.png |
Full gallery (64 screenshots, light + dark, desktop + mobile) in 🖼️ Screenshots. Live verification notes in docs/LIVE_VERIFICATION.md.
Phase 18.3 — AI Evaluation Framework
- Evaluation Metrics —
EvaluationMetricmodel with metric_key (unique), metric_type (deterministic/heuristic/llm_judge), category, formula,is_higher_betterdirection, default_threshold;register_metric()service with idempotent create/update - Golden Datasets —
EvaluationDatasetversioned withUniqueConstraint(dataset_key, version), status lifecycle (draft→published→archived),EvaluationCasewith input/expected_output/expected_labels/metadata/evaluation_criteria;create_dataset(),create_dataset_version()(clone),publish_dataset(),archive_dataset(),add_cases()services - Evaluator Abstraction —
evaluators.pywithregister_evaluator()/get_evaluator()/evaluate_case()dispatcher; 26 built-in evaluators: search (precision@K, recall@K, NDCG, MRR, relevance_score), classification (accuracy, precision, recall, F1), fraud (precision, recall, F1, FPR, FNR), LLM (task_success, relevance, completeness, hallucination_rate, structured_output_validity), general (exact_match, contains, length_ratio), prediction (MAE, RMSE, R²) - Evaluation Runs —
EvaluationRunwith UUID run_key, status lifecycle (pending→running→completed/failed/cancelled),EvaluationCaseResultwith per-metric results, composite score, pass/fail, latency, error tracking;create_evaluation_run(),execute_evaluation_run(),cancel_evaluation_run()services;execute_evaluation_run_taskCelery task for async execution - Thresholds & Regression —
EvaluationThreshold(unique per feature+metric),check_regression()compares run metrics against thresholds,get_latest_baselines()for baseline tracking - Model/Prompt Comparison —
compare_runs()(side-by-side),compare_models()(same feature, different models),compare_prompts()(same feature, different prompts),compare_with_baseline()with delta analysis - Admin API — 17 new endpoints under
api/v1/ai/eval/: metrics, datasets, cases, thresholds, runs (CRUD + execute + cancel), case results, comparisons, regression check, baselines - Celery —
execute_evaluation_run_task(async run execution),cancel_stale_evaluation_runs(every 30 min, cancels runs stuck >1 hour) - Engineering — 44 new tests (107 ai_intelligence total), 6 new models, 1 new app file (evaluators.py), migration 0005, ruff-clean. See
docs/phase-18-3-evaluation-framework.md
Phase 18.2 — AI Intelligence Foundation (Prompt Registry + Feature Integration)
- Prompt Registry —
AIPrompt+AIPromptVersionmodels: versioned prompt/template management withUniqueConstraint(prompt, version), one active version per prompt,activate/deactivate/rollbacklifecycle, template safety validation (rejectsAPI_KEY/SECRET/PASSWORD/TOKEN/PRIVATE_KEY/AWS_/OPENAI_API/ANTHROPIC_APIpatterns),render_prompt()for{{variable}}fill,validate_prompt_variables()for missing/unused variable detection, immutable templates after creation - Feature Flag Integration —
is_feature_available(feature_id)now checks bothAIFeatureRegistry.is_enabledAND linkedFeatureFlag.is_enabled()(lazy import to avoid circular deps),AIFeatureRegistryextended withstatus(active/deprecated/disabled),owner,default_model,fallback_strategy,feature_flag_key - AI Feature Seeding —
register_ai_featuresmanagement command seeds 30 real AI features from codebase audit (NLP, recommendation, pricing, vision, fraud, KYC, embedding, matching, agreements, analytics) - Expanded Admin API — 18 endpoints under
api/v1/ai/: 3 feature (list/detail/update), 7 prompt (CRUD + versions), 2 log (list/detail), 3 health (list/stats/update), 3 version management (activate/deactivate/rollback) - Engineering — 63 ai_intelligence tests, 4 database migrations, ruff-clean, existing 1312 tests all pass (was 1270). See
docs/phase-18-2-prompt-feature-registry.md
Phase 18.1 — AI Intelligence Foundation (Provider Registry + Telemetry)
- AI Intelligence Layer — new
ai_intelligenceDjango app:AIFeatureRegistry(central registry of all AI features, providers, costs, settings),AIExecutionLog(append-only per-request telemetry with UUID execution_id, latency, tokens, cost, confidence, fallback chain tracking, 4 composite DB indexes),ProviderHealth(aggregated provider availability/failure rates over time windows with p95/p99 latency, unique constraint per provider+feature+window) - TelemetryMixin — drop-in mixin for any
BaseProvidersubclass: automatic execution timing (timed_executioncontext manager), non-blocking telemetry logging toAIExecutionLog, configurable viaAI_TELEMETRY_ENABLEDsetting (defaultTrue), lazy DB import so providers work without telemetry when flag is off - Enhanced ProviderResult — new fields:
latency_ms,input_tokens,output_tokens,model_name,model_version,estimated_cost_usd,failure_type(backward-compatible defaults);ok()andfail()class methods extended with optional telemetry kwargs - Cost estimation —
calculate_estimated_cost(provider, model, tokens)utility with published pricing for OpenAI (GPT-4 family) and Anthropic (Claude 3 family); returnsDecimalin USD, 0 for unknown models - Provider stats API —
get_provider_stats(feature_id, provider, hours)aggregates execution logs into success rate, avg/p95 latency, total cost, total tokens, with per-provider breakdown - Admin API — 7 read-only endpoints under
api/v1/ai/(feature list/detail, execution log list/detail, provider health list, stats, manual health update), all staff-only - Celery beat tasks —
update_provider_health(hourly aggregation of execution logs intoProviderHealth),purge_old_execution_logs(daily cleanup of logs older thanAI_EXECUTION_LOG_RETENTION_DAYS, default 90) - Provider health aggregation — calculates success rate, p95/p99 latency, timeout counts, token totals, cost totals per (provider, feature) combination; marks providers unhealthy when success_rate drops below 95%
- Engineering — 21 new tests, 3 database migrations, ruff-clean, existing 1270 tests all pass. See
docs/phase-18-ai-intelligence-audit.md
Phase 17 — Graph & Deep Trust (ML Anti-Fraud v2)
- Scam-network graph —
GraphNode/GraphEdgemodels (PostgreSQL, no external graph DB),rebuild_graphfull rebuild +update_graph_incrementalon fraud events, community detection (Union-Find), admin API (/api/v1/fraud/graph/— nodes, edges, rebuild, anomalies). Feature-flagged viaGRAPH_ENABLED - KYC liveness + face-match —
LivenessChallenge/LivenessConsentmodels, pluggable providers (rulesdeterministic,httpgateway), OCR confidence thresholds, 5 API endpoints (/users/liveness/),purge_expired_livenessbeat task. Feature-flagged viaKYC_LIVENESS_ENABLED - Photo-geo authenticity —
RoomImageGPS fields,photo_geoservice (haversine mismatch detection),scan_photo_geo_mismatchesCelery task,PhotoGeoMismatchesViewadmin endpoint. Feature-flagged viaPHOTO_GEO_ENABLED - Fake-review detection —
review_detectorservice (trust scoring: age/length/contact/spam/velocity/similarity, anomaly detection),scan_review_trust+detect_review_anomaliesCelery tasks. Feature-flagged viaREVIEW_TRUST_ENABLED - Model drift monitoring —
model_monitorservice (check_all_drift, DriftMetric recording, retrain-request creation),check_model_driftbeat task, admin drift/retrain endpoints. Feature-flagged viaMODEL_DRIFT_ENABLED - Shared provider abstraction —
BaseProvider/ProviderResult/ProviderFailure/Registryinfraud/services/provider_base.py; all providers (liveness, face-match, OCR) share a common failure taxonomy (USER_FAILURE/PROVIDER_FAILURE/SYSTEM_FAILURE) - Security/privacy — PII masking (phone, NID, email), reason sanitization, audit logging, sensitive-field scrubbing from logs/analytics/URLs/CSVs;
ProviderResult.fail()auto-sanitizes - Engineering — 262 new backend tests (350 fraud total), 10 stages, pre-commit ruff-clean, Celery beat schedule updated. See
docs/phase-17-final-report.md+docs/phase-17-graph-trust-audit.md
Phase 16 — Hardening & Scale
- Embeddings & pgvector (vendor-guarded) —
embeddings/app:vector(384)field on PostgreSQL with a JSON-text fallback so SQLite dev/CI stays green, content-hash dedupe, HNSW index,index_room/remove_room/backfill_roomstasks +backfill_embeddingscommand; smart-search_vector_rankseam and publicGET /api/v1/rooms/{id}/similar/. Controlled byVECTOR_SEARCH_ENABLED(default off) - Feature flags + A/B experiments —
feature_flags/(cache-backedis_enabled, staff CRUD at/api/v1/flags/,sync_flagsseeder) andexperiments/(deterministic bucketing, persisted assignments, idempotent exposure/conversion wired to the analytics event store, throttled API at/api/v1/experiments/) - Image pipeline / CDN —
images/app generating WebP variants (320/640/960/1280), content-hash filenames for immutable 1-year browser caching, upload hardening (magic-bytes + bomb-guard decode, 128–8000 px bounds, 5 MB cap, max 10 images/listing); KYC/tenant documents moved to private storage (out of the public media root); frontend renderssrcsetWebP variants with lazy loading - Redis hardening —
KEY_PREFIXnamespacing, connection-pool/socket timeouts +protocol=2, channel-layer prefix; chat presence re-architected to a self-healing lease model (per-connection heartbeats, TTL expiry — a crashed worker can no longer leave users stuck "online"); bKash grant-token single-flight lock; booking create overlap re-checked underselect_for_update(closes the double-booking race) - Rate limiting / abuse — proxy-aware client-IP resolution (
NUM_PROXIES, XFF opt-in), trusted throttle classes wired site-wide,experimentsscope actually enforced (was a no-op), 429 envelope verified - Celery reliability — broker retry on startup, ack-late + reject-on-worker-lost, soft/hard time limits, default retry policy; prod warns loudly if the broker URL is missing
- App hardening —
/health/liveness endpoint (DB probe, no auth/throttle),X-Request-IDcorrelation middleware, 10 MB request body limits - Engineering — 4 new apps (
embeddings,feature_flags,experiments,images), ~12 migrations, 960 backend tests passing, frontend tsc/eslint clean. Seedocs/phase-16-hardening.md
Phase 15 — Monetization 2.0 (Revenue)
- Landlord SaaS — subscriptions & entitlements — plan catalog (monthly/yearly), self-serve checkout via SSLCommerz/bKash with server-side pricing, subscription activation tied to a confirmed payment (atomic), cancel-at-period-end + renewal, and entitlements enforced server-side (
SUBSCRIPTION_FREE_FEATURES); the AI price-prediction v2 endpoint is gated behindprice_prediction_basicwith a graceful free-tier fallback. Seedocs/phase-15-monetization-2.0.md - Revenue ledger & commission engine — idempotent
RevenueLedgerEntry+Commissionrecords (uniqueidempotency_keyso a booking/order can never double-credit), platform/partner splits per scope with default rates (broker 2.0%, corporate 1.0%, marketplace 10%, insurance 8%, credit 3%), a payout lifecycle (pending → approved → paid / rejected) that deducts the balance atomically and masks account details, and a Celery-beat subscription renewal + reminder pipeline - Verified Broker/Agent Network — broker profiles with license + referral code, rule-based auto-screen verification, attributed booking commissions (signal-driven, idempotent), broker dashboard (balance, pending/paid, recent commissions) and self-serve payout requests
- B2B Corporate Housing — corporate accounts (pending/active/suspended), member invites, bulk booking with partial success, corporate invoices (draft → generate), company-admin overview/approvals and platform-admin controls
- Add-on Services Marketplace — provider registration, category-filtered service catalog, order lifecycle (pending → confirmed → completed/canceled), per-booking AI cross-sell recommendations and provider commission
- Insurance & Credit Partnerships — provider-agnostic partner abstraction with a rule-based insurance provider: instant quotes, issue/decline/cancel policies, product catalog, and renter credit eligibility (pre-approved limit); every action auditable
- Admin revenue centre — revenue dashboard (gross/platform revenue, MRR, pending partner obligations), live ledger, and a payout queue (
/dashboard?tab=revenue) - Engineering — 6 new backend apps (
subscriptions,monetization,brokers,corporate,marketplace,partner_services), 11 migrations,manage.py seed_monetization, renewal/reminder beat tasks, 884 backend + 373 frontend tests, tsc/eslint/prettier clean. Frontend:/servicespage + Dashboard tabsmonetization/broker/corporate/revenue, EN/BN i18n
Phase 15 — Communication & Trust AI
- Chat translation (B1) — auto-detects source language, translates chat messages EN↔BN with Google Translate fallback; quality flag (
full/phrase/none) shown honestly in the UI - Support copilot (B2) — grounded FAQ matcher against help library; returns answer + Bangla translation + matched keywords; honest fallback when no article matches
- Voice TTS (B3) — Web Speech API integration on copilot assistant replies; respect
speechSynthesisavailability with feature-detection guard - KYC OCR (C4) — auto-extracts NID number, name, DOB from uploaded verification documents with confidence score; displayed in TenantKycCard with honesty note
- Review summary (C5) — AI-generated summary of room reviews with sentiment breakdown (positive/neutral/negative %) and topic tags; shown in ReviewsSection
- Market report (C6) — weekly area-level rental analytics (median price, WoW movement, index); AdminAnalyticsPanel visualization; email distribution to opted-in landlords
- Dynamic pricing v2 (C7) — demand-momentum-adjusted price windows with area-specific factor drivers; replaces static v1 with time-series-informed recommendations
- Fraud rings (D8) — detects coordinated accounts via shared phone (strong link) and shared audit IP + same area (weak link); flagged rings surfaced in AdminFraudPanel
- Bug fix — fixed SQLite
DISTINCT+ORDER BYgotcha inmarket_report.pyandforecast.py; added.order_by("area")to deduplicate area rows
Phase 14 — AI v3: Vision & Content AI
- Photo intelligence —
rooms/vision.pyfingerprints a listing's photos (pHash + 64-bucket colour histogram + brightness + palette, Pillow-only, offline) and derives honest, confidence-scored observations: lighting, tone, décor, composition.POST /api/v1/rooms/<id>/vision/analyze/stores aRoomVisionAnalysis(OneToOne),GET /vision/serves it,POST /vision/description/drafts a copy-ready title + description from the actual photos (reuses the AI draft pipeline with the vision image profile), and suggested amenity tags can be reviewed then applied to the listing. Object-level tags need an optionalhttpvision gateway (VISION_PROVIDER=http) with graceful fallback; every response carries the honesty note that this is statistical pixel vision, not object recognition. Seedocs/phase-14-ai-v3.md - AI image search —
POST /api/v1/rooms/vision/search/(public, throttled 30/min): upload any room photo, get look-alike listings ranked 50% phash + 25% histogram + 25% brightness with match scores and reasons; the rooms grid shows88% matchbadges. - Frontend —
VisionCardpanel in the landlord dashboard (My Listings) with palette swatches, evidence chips, Apply tags, AI draft + copy; Image search dialog on/roomswith photo preview and results mode; all strings in English + বাংলা. - Engineering — 716 backend (was 689) + 342 frontend (was 333) tests, tsc/eslint/prettier clean, migration
rooms/0007_roomvisionanalysis.py, 3 new Playwright screenshots (capture_phase14_shots.mjs).
Phase 13 — Reach (SMS OTP, WhatsApp sharing, area SEO)
- SMS OTP sign-in — phone-first login for the Bangladesh market:
POST /api/v1/auth/sms/request|verify/with a SHA-256-hashed challenge (TTL 600s, max 5 attempts, 30s resend cooldown), masked-phone responses (+8801••••78) and auto-registration for new numbers. Provider contract (users.sms.send_sms) shipsconsole(logs the code — zero-config dev/CI) andhttp(generic gateway POST); disabled by default (SMS_OTP_ENABLED=False→ endpoints answer503until a real gateway is plugged in). 19 tests including the disabled→503 path. Seedocs/phase-13-reach.md - WhatsApp listing share with AI summary — Share on WhatsApp on every room card + in the room modal.
GET /api/v1/copilot/share-summary/<id>/builds a compact, deterministic summary only from public listing fields (no owner contact details); the frontend falls back to a client-side summary when the AI call fails, then openswa.me/?text=…pre-filled with the summary + deep link. - Per-area SEO landing pages —
/rooms/:areaSlugfor 10 Dhaka areas (own<title>"Rooms for rent in Dhanmondi, Dhaka", meta description, live room grid,?room=<id>deep links), a navbar Areas dropdown,npm run generate:sitemap→public/sitemap.xml(5 core + 10 area routes), androbots.txtupdated. Honest limits: SPA, not SSR — the area pages are crawlable metadata + sitemap. - Lighthouse gate in CI —
scripts/lighthouse-gate.mjsaudits the built app (chrome-launcher,--min-scorethreshold 70; local run 70/70 PASS) and a newlighthouseCI job uploads the report as an artifact. - Engineering — 689 backend (was 667) + 333 frontend (was 322) tests, tsc/eslint/prettier clean, migration
users/0010_smsotpchallenge.py. React Native remains a separate, unfunded track (docs/MOBILE_APP_PLAN.md).
Phase 12 — Trust & Safety V2 (Marketplace Integrity)
- Tenant KYC + verified-tenant badge — tenants upload a NID/passport (multipart, MIME/size-validated, UUID-renamed private storage); statuses not_started → pending → verified / rejected / needs_review / expired. Landlords only ever see the ✓ Identity Verified badge — never the document, the NID number, or the file URL. Admin queue (
/admin/trust/tenant-verification) with approve/reject/resubmission, each decision audited (tenant_kyc.*) and notified. Badge renders in chat, booking requests and the tenant profile. Seedocs/TENANT_KYC.md - Chat safety engine — the fraud engine now analyses every chat message: suspicious payment requests, payment/bKash redirects, phishing URLs, contact-info harvesting, impersonation, scam phrases and urgency. Outcomes: LOW (allow) / MEDIUM (warn banner) / HIGH (flag + warning) / CRITICAL (blocked message, replaced with a safety notice — never silently deleted). Admin feed
GET /chat/safety/events/(metadata only, no raw content). Seedocs/CHAT_SAFETY.md - Report / block / dispute — report a user, message (anchored to the exact message) or listing across 7 categories (scam, harassment, fake listing, payment fraud, impersonation, spam, other); block/unblock a user closes the conversation both ways (server-enforced); structured moderation tickets with admin warn / restrict / suspend / escalate actions — all audited (
report.*,user.blocked) and both parties notified - Photo + review moderation — the moderation app auto-scores every new review (URLs, phone/email, spam phrasing, all-caps/exclamation, gibberish, cross-user duplicate text, review velocity) and photo (pHash duplicate-image reuse, blank-image guard) — high-risk content is held in a moderation queue instead of published; admin approve/reject with notes, audited (
content_moderated) and the author notified - Dispute resolution + deposit protection — one structured dispute per approved booking (6 categories: deposit, property condition, cancellation, misrepresentation, payment, other) with participant-only evidence (text/photo/document, IDOR-guarded), a full status lifecycle, and admin resolution (release-to-landlord / refund-to-tenant / partial) that marks the booking deposit released/refunded. Wording is honest — the platform never claims "escrow". See
docs/phase-12-trust-safety-v2.md - Admin Trust & Safety Operations Center — one dashboard (
/dashboard?tab=trust) aggregating KYC pending, chat-safety events, open reports, moderation queues and open disputes with sub-tabs into each queue, plus the generic read-only audit trail (GET /api/v1/audit/) covering every Phase 12 decision - Engineering — 3 new backend apps (moderation, disputes + audit endpoint) and 6 new frontend admin/user panels; 473 backend + 312 frontend tests, tsc/eslint/prettier clean
Phase 12 P0 — Progressive Web App (installable app)
- Installable PWA —
manifest.webmanifestwithstandalonedisplay,#ea580ctheme (design-token brand), 192/512 standard + maskable icons, Apple-touch + favicon set (32→144), generated reproducibly from the brand (scripts/generate_pwa_icons.py) and validated in CI against the built app (scripts/validate-pwa.mjs) - Native install experience — the browser's
beforeinstallpromptis captured but suppressed until a subtle navbar "Install app" CTA is clicked, so Rentora never fires a surprise popup; the CTA disappears after install, and a dismissal cools off for a week (usePwaInstall) - Standalone + deep links — works installed on desktop & mobile; routing, auth, the map (viewport/radius/destination URL sync), voice search, Copilot and both dashboards behave identically in standalone mode
- Safe service-worker caching — the push worker now also caches a versioned
rentora-static-v1app shell + static assets only;/api/*(auth, private, admin, fraud, payment) is never cached, navigations are network-first with an offline shell fallback, and only our ownrentora-static-*caches are ever cleaned - Update UX — when a new build takes over, a "A new version of Rentora is available [Refresh] [Later]" banner appears (Later remembered for 24h); the initial install never shows it (
usePwaUpdate) - Graceful offline — an amber "You're offline" banner (safe-area aware) while already-loaded UI stays visible — never fake listings or stale data
- Shortcuts — Search Rooms
/rooms· Explore Map/map· Post Listing/dashboard?tab=listings - Branding — the app name is now Rentora 🇧🇩 (gradient wordmark in the navbar/footer, Bangladesh-flag badge) matching the push notifications, Copilot and README
- Engineering — 11 new unit tests (
src/lib/pwa.test.ts), PWA validation wired into the Frontend CI job. Seedocs/PWA.md
Phase 12 P1 — Offline & App Polish
- Offline search — the Rooms page now serves from an IndexedDB cache of PUBLIC listings (24 h TTL, room details 7 d) with client-side re-filtering when the network drops, plus a "📡 showing N cached of M (offline)" pill; auth/private/admin/fraud/payment data is never cached (
rentora-offlineDB holds only public room lists/details + the action queue) - Background sync — offline actions (wishlist toggles, saved-search checks) are queued and replayed on reconnect via
registration.sync+online/visibilitychangefallbacks; failed replays are re-queued, never dropped - Periodic Background Sync (research-informed, feasible subset) — when installed, Chromium-only daily
rentora-refreshkeeps the PUBLIC cache fresh; Notification Triggers API documented as future scope (not shipped in any browser) - Splash screens — 11 device-matched Apple splash screens + dark maskable icon (
maskable-dark-512), all generated from the brand byscripts/generate_pwa_icons.py - iOS install hint — one-time, dismissible "Add to Home Screen" card (Safari has no install-prompt API)
- Flag everywhere — brand name now uses an inline SVG Bangladesh flag (
BangladeshFlagcomponent) that renders identically on every OS — no more "BD" letters where the emoji is missing - Lighthouse (prod build) — Performance 84 · Accessibility 93 · Best practices 96 · SEO 82 (
robots.txtadded); Lighthouse 12+ dropped the PWA category — installability enforced by CIvalidate-pwa.mjsinstead - Engineering — 17 new unit tests (230 frontend total), tsc/eslint/prettier clean
Map Intelligence v3 (Phase 7 v3) — Interactions + Dark Mode + Dhaka Hierarchy
- Dark map fixed — lifted CARTO dark raster paint (brightness floor 0.2, contrast 0.2) keeps roads + street labels readable instead of near-black; dark-fallback also lifted; overlays now visible in dark mode
- Dark layer contrast QA — every overlay gets dark-mode paints via a theme-swap effect (
setPaintProperty, map state preserved): 🎓/🚇 dots brighten, MRT corridor core brightens with subtle casing, heatmap switches to green-400/amber-400/red-400 at higher opacity with dark strokes, cluster rings darken, isochrone bands get stronger fills (0.1 → 0.22) + white outlines, radius/metro-reach rings brighten; dark popup card (no more white flash); paint values inlib/mapInteractionsTHEME_PAINTS(unit-tested) - Every map element is interactive now — click a 🎓 university or 🚇 metro station → real nearby stats (count · avg/range rent within ~2 km) + "Find rooms near…" CTA; MRT Line-6 corridor clickable; price-heatmap click → clicked area's real stats; 10/20/30-min walking bands clickable → rooms inside
- Map ↔ list sync — list click flies + highlights the pin; map pin click scrolls the list item into view
- Room deep links —
?room=123in a shared map URL reopens the listing on load - Structured Dhaka hierarchy — new
GET /api/v1/rooms/area-hierarchy/(20 main areas → 30+ sub-areas/neighbourhoods, parent links, Bangla + English aliases); sub-area search ("Mirpur 10", "Uttara Sector 7", "ধানমন্ডি ২৭") resolves with its parent district shown - Area boundary polygons —
GET /api/v1/rooms/area-boundaries/: approximate boundary bubbles (honest circles,approx_radius_km, not fake borders) — main areas strong orange rings (z≈9.5+), sub-areas blue (z≈11.5+), neighbourhoods violet (z≈13.5+), click → real area stats; dark-mode paints included - Expanded landmark layer — 🏥 hospitals, 🛒 markets, 🌳 parks, 🕌 mosques, 🚌 bus terminals join universities & metro (63 real Dhaka places: Square Hospital, New Market, Baitul Mukarram, Gabtoli/Saidabad terminals…). Everyday categories share one clustered source: count bubble at low zoom (click → zoom in) → per-kind dots as you zoom, each with its own minzoom; every dot opens real nearby-room stats + "Rooms near here →" radius CTA; dark mode brightens each category
- Nearby-landmark chips — every listing popup shows the nearest useful places around it (🚇 7 min Metro · 🎓 12 min University — real landmarks only, nearest of each category within ~3 km, honest walk estimates); clicking a chip flies to the place + starts a radius search
- Zoom-aware area labels — area bubbles carry their real centre (
lat/lng), rendered as labels with zoom-based hierarchy (main z≈10, sub z≈12.5, neighbourhood z≈14.5) so the map never drowns in text; theme-aware text + halo - Boundary click → area filter — clicking an area bubble highlights it (selected > hover > base feature-state), shows its real stats and filters the room list + URL (
?area=…); empty click clears it - Landmark-nearby list search — filter the room list by "near a metro / university / hospital…" within 0.5–2 km (
?near=<kind>&distance=<km>), resolved to the nearest real landmark, map flies there once
Phase 9 — Operate It (Reliability & Observability)
- Sentry error tracking — backend (Django/Celery integrations) and frontend (
@sentry/react); initialised fromSENTRY_DSN/VITE_SENTRY_DSNand a no-op when unset, so local dev and CI never send events. Frontend error boundary forwards component stacks. - Structured JSON logging — a stdlib-only
JSONFormatter(config/logging.py) emits one JSON object per line whenJSON_LOGS=True; stable keys (timestamp/level/logger/message) plus caller extras, ready for any log shipper. - Celery + Celery Beat —
config/celery.pywith a zero-config local mode: an emptyCELERY_BROKER_URLruns tasks eagerly (synchronously, no Redis), production sets a Redis broker and tasks go async. Scheduled maintenance moved onto the beat schedule: hourly tier expiry, daily market-stat refresh, daily catalogue fraud re-scan, daily rent reminders (rooms/pricing/fraud/payments/tasks.py). - Fraud hardening — the auto-scan now runs through a Celery task wrapped in try/except so a detector or queue failure can never break room creation; individual detector failures are isolated (logged + skipped, the rest still run); the flag path now also emails the landlord.
- Branded HTML transactional emails —
notifications/emails.py+notifications/templates/emails/(base shell + OTP code, recovery codes, booking status, fraud flag, promotion expiry), each with a plain-text fallback. Wired into OTP delivery, 2FA-enable recovery codes, booking lifecycle signals, fraud flags, andexpire_listings. - Audit log — new
auditapp: an append-onlyAuditLogEntrytable records who did what to which object (with IP) for sensitive actions. Wired into fraud-report review and 2FA enable/disable; the Django admin view is read-only so the trail cannot be rewritten. - Backup & restore runbook —
scripts/backup_db.py(cross-platform; SQLite consistent copy via the backup API, PostgreSQL viapg_dump, pruning with--keep) plusdocs/ops/backup-restore.mdcovering restore, media, and a quarterly restore drill. - KYC SLA breach alerts — a daily Celery beat task (
alert_kyc_sla_breaches) watches the KYC review queue and alerts every admin (in-app notification + branded email) when a breach fires: an application stuck past 48h, or decisions this week trailing last week. Deduplicated atomically per day per condition (get_or_createon a date-stamped title), so a retried cron never stacks identical alerts.
Phase 10 — Grow It (Growth & Personalization)
- AI recommendations v2 — Similar Rooms — every room modal now shows a content-based similar-rooms carousel (
GET /recommendations/similar/<id>/): listings ranked by area, room type, price band and amenity overlap, with a match % and explainable reasons ("Same area: Dhanmondi · Similar amenities"). Same feature vector family as the personalized recommendations, so the two surfaces agree. - Search v2 — full-text + typo tolerance — room search (
?q=) is now real full-text on PostgreSQL (SearchVector/SearchRankwith stemming +pg_trgmfuzzy similarity so typos still match) with an automaticicontainsfallback on SQLite, so dev/CI/prod behave identically.?q=still composes with area/price/gender filters and geo queries. - Saved searches + alerts — the Rooms page gets a Saved searches bar: save the current filters (with a name), and a daily Celery beat task (
check_saved_searches) notifies you in-app whenever a new matching listing appears (never re-alerts the same rooms —last_checked_atadvances every run). Manual "check now" from the list too. - Browser push notifications — subscribe once from the Dashboard (Browser notifications card) and every in-app notification (bookings, chat, fraud flags, KYC decisions, saved-search matches) is also pushed to your browser even when Rentora is closed. VAPID keys generated by
scripts/generate_vapid.py(pywebpushserver-side +public/sw.jsservice worker); dead subscriptions are auto-pruned (410 Gone), and no VAPID = safe no-op for local dev/CI. - Referral program — every account gets a unique referral code; share your invite link (Dashboard → Invite friends card, with WhatsApp/Facebook shortcuts) and signups landing with
?ref=CODEare attributed to you (GET /users/referral/shows your code, link and who joined).refis optional at register — the code is just a query param on the shared URL. - Wishlist sharing — one tap Share wishlist copies a public, unguessable link (
/wishlist/share/<token>/) — room summaries only, no personal info, 404 on bad tokens so they can't be enumerated. - Landlord tools — listing insights — new Dashboard Insights tab: per-listing engagement (views 7d/30d tracked from room-detail visits, deduplicated), wishlist saves, booking requests vs approvals, and price vs area-average positioning (from the market-stats table) with a red/green delta badge — plus bulk listing creation (
POST /rooms/bulk/). - Reviews v2 — replies, photos, rating breakdown — reviews now support landlord replies (inline form for the room owner, shown under the review), tenant photo reviews, and the room modal shows a rating breakdown (5★ histogram + average + verified-stay badges) from
GET /reviews/summary/?room=. - Engineering — 388 automated tests (210 backend + 178 frontend), ruff/eslint/prettier clean, migrations include a backfill so every existing account gets a unique referral code + wishlist token.
Tier-1 Quick Wins (polish batch)
- Chat: message search + edit/delete (audited) — search any message in a
conversation, edit your own text messages (re-runs the chat-safety engine),
and soft-delete messages. Every edit/delete writes an audit entry
(
chat.message.edited/chat.message.deleted) and updates all open clients in real time over the WebSocket. - Saved-search daily email digest — one branded email per day with new
listings matching your saved searches (deduped across searches, own
listings never emailed, per-account opt-out
digest_emails_enabled), delivered through the rate-limited alert email guard. - Report/block abuse guard — the report endpoint is now rate-limited (10/hour) and a duplicate report of the same target while a report is still open returns the existing ticket instead of stacking the queue.
- Semantic search cache — identical smart-search / Copilot queries over the same room pool reuse the cached ranking instead of recomputing embeddings (personalized + debug requests bypass the cache).
- Security headers + security.txt — CSP,
Referrer-Policy,nosniff,Permissions-Policyand HSTS (prod) on every response; RFC 9116/.well-known/security.txt. - Dependency bump audit — safe patch/minor bumps applied to backend +
frontend deps and documented in
docs/tier1-dependency-audit.md(majors like React 19 / Vite 8 / Django 6 held for a dedicated upgrade cycle).
Tier-3 Upgrades (RAG Copilot, i18n, embeddings, E2E, trust signals)
- RAG-powered Copilot (listing mode) — the Copilot is no longer
search-only: from any room modal, Ask Copilot about this listing opens
a conversation grounded on that single listing (
listing_idonPOST /api/v1/copilot/chat/, fact card atGET /api/v1/copilot/listing/<id>/). Questions about price / amenities / area / type / size / gender / verification / availability are answered strictly from the listing's public fields (bilingual keyword detection, EN + BN + Banglish); anything the listing doesn't state is refused explicitly — no hallucination by construction. Deterministic map intel (nearest metro) included in the fact card. - Full EN ⇄ বাংলা UI toggle —
react-i18next+i18nextwith inline dictionaries (src/i18n/en.json/bn.json), a বাংলা/EN toggle in the navbar, language persisted inlocalStorageand applied before first render (no flash of the wrong language),document.documentElement.langset for accessibility, and English fallback for any untranslated key. Core surfaces translated: navbar, footer, home hero, room cards, room modal, copilot widget, trust badges, search labels. - Production-grade neural embeddings —
SEMANTIC_EMBEDDING_MODE(auto/neural/lite) selects the provider, the embedding matrix is persisted to disk keyed by provider + data fingerprint (SEMANTIC_EMBEDDING_CACHE_DIR, defaultmedia/embeddings) so every worker reuses the prebuilt neural matrix instead of re-encoding the corpus and re-downloading the model, andpython manage.py prebuild_embeddingswarms the cache after deploy.neuralmode degrades to lite with a warning when sentence-transformers is missing — search never breaks. - E2E suite expansion (trust-flow + map) — new tagged E2E tests driving
the real API: the full trust chain (report → duplicate-report guard →
admin queue → dismiss → block → chat refused → unblock → audit trail,
with
report.created/user.blocked/user.unblockedaudit events added where the spec required them) and the map flow (map search → area stats → commute ETA with OSRM-off graceful fallback). - Tenant behavioral trust signals — transparent, data-backed signals
beside the identity badge: completed bookings (approved bookings whose
deposit was refunded or stay ended — never pending/in-progress),
exposed as
trust_signalson the user details, chat participants and booking payloads, and rendered as a ✓ N completed bookings chip in chat headers, the verified-tenant badge and the landlord dashboard. - Engineering — 610 backend + 320 frontend tests, ruff/eslint/tsc clean.
Tier-4 Upgrades (AI tools, comparison, forecast, Playwright E2E, hosted KYC)
- 🤝 AI Rental Advisor (
POST /api/v1/copilot/advisor/) — budget + income in → a grounded, transparent budget plan (rent cap, suggested areas, monthly breakdown) built from live listing data, never invented figures. - 💬 AI Negotiation Assistant (
POST /api/v1/copilot/negotiate/) — picks the right counter-offer bracket from comparable listings in the same area and drafts a polite EN/BN message the tenant can send directly from the listing modal (Draft negotiation). - 📄 AI Rental Agreement Checker (
POST /api/v1/copilot/agreement-check/) — paste a rental agreement; deterministic rules flag one-sided clauses, advance-payment risk and missing Bangladesh-standard fields (refund terms, notice period, deposit return), with plain-language advice. - 🏠 Landlord Copilot (
POST /api/v1/copilot/landlord/) — landlord-facing insights for any owned listing: price position vs the market median, listing-quality score, occupancy risk and pricing suggestions. - 📊 AI Property Comparison (
GET /api/v1/rooms/compare/?ids=1,2) — select 2–5 rooms and compare price, size, amenities, ratings and per-area value in a dedicated drawer with clear winner call-outs. - 📈 Demand Forecasting (
GET /api/v1/analytics/forecast/) — lightweight time-series forecast of rental demand for an area + room type, powering smart alerts and landlord insight. - 🔔 Smart AI Alerts (
GET /api/v1/notifications/smart/) — your notification inbox re-ranked by a transparent priority score (0–100) with a plain-languagereasonfor every item. - 🧠 Hosted neural embeddings —
SEMANTIC_EMBEDDING_PROVIDER=hosteduses a remote Hugging Face endpoint (falling back to local lite mode gracefully); the disk-persisted matrix stays the single source of truth. - 🪪 Automated KYC pre-verification — a pluggable provider
(
USERS_KYC_PROVIDER, mock/auto modes) pre-screens NID submissions with deterministic checks (document number shape, date sanity, duplicate guard), auto-approves only clear passes and routes everything else to the existing manual admin review — the human fallback is always in place. - 🧪 Browser-level Playwright E2E — a real-browser layer (
frontend/e2e,npm run test:e2e) that boots the dev server and verifies the app renders, searches, opens the Copilot and answers a listing question; wired into CI as a separate job. - Engineering — 667 backend + 322 frontend tests (989 total), ruff/eslint/tsc clean, OpenAPI↔TS schema contract enforced.
Tier-5 Upgrades (funnel analytics, photo forensics v2, price advisor, Copilot vision, AI drafts)
- 📈 Conversion funnel fully wired — the last missing analytics steps are
now emitted server-side:
booking_confirmed(on approval, via the booking signal) andpayment_completed(on the payment SUCCESS transition) join the client-firedpage_view→room_view→chat_started→booking_requestedsteps, so the self-hosted analytics funnel reflects real conversion (667 backend tests verify attribution + no-PII). - 🖼️ Photo forensics v2 — the existing ELA/watermark-band pipeline gains two deterministic heuristics: text-overlay detection (dark strokes on a bright photo — captions/phone-number watermarks) and repeated-pattern detection (tiled/diagonal watermarks that real photos never contain), both tuned against synthetic attacks and the existing clean-photo suite.
- 💹 Per-listing price recommendation (
GET /api/v1/rooms/<id>/price-recommendation/, owner/admin) — the demand-forecasting engine is now linked to individual listings: area demand index + market position + the listing's own 30-day interest signals produce a grounded raise/hold/lower verdict with a suggested price and plain-language reasons (a review aid, never an automatic change). - 👁️ Copilot image understanding — ask "দেখতে কেমন? / what does it look like?" and the listing-mode Copilot answers from the actual photos using deterministic pixel statistics (brightness, colourfulness, dominant tones), explicitly labelling the answer as statistical — no invented captions.
- ✍️ AI listing draft (
POST /api/v1/rooms/generate-description/) — landlords get a one-click ✨ AI draft in the listing form: a title + description + amenity tags built deterministically from the fields they've already filled, always editable before publishing. - Engineering — 667 backend + 322 frontend tests (989 total), ruff/eslint/tsc clean, OpenAPI↔TS schema contract enforced.
Tier-2 Medium Upgrades (trust, analytics & infra)
- AI chat-safety classifier — a learned Naive-Bayes layer (trained on
real EN+BN rental conversations, Unicode-aware tokenization) sits on top
of the deterministic rules: it flags scam-like messages the rules miss,
can only ever flag for human review (never block), and every model
mistake degrades to a queue item. Toggle:
CHAT_SAFETY_ML_ENABLED. - Self-hosted analytics — first-party event capture (
POST /api/v1/analytics/events/, auth-optional, bounded payloads, throttled, no PII) + admin dashboard (GET /api/v1/analytics/summary/): event totals, top events/pages, daily volume and the conversion funnel (page_view → room_view → chat_started → booking_requested → booking_confirmed → payment_completed, distinct users per step). New Analytics tab in the Trust & Safety Operations Center. - Photo manipulation / watermark detection — pure-Pillow forensics on
listing images: block-level ELA consistency (catches the classic
multi-generation paste attack without flagging honest recompression),
watermark-band / editor-EXIF / tiny-low-quality heuristics. Wired into
the fraud scan as the
manipulated_imagedetector. - OSRM commute ETA — real road-network ETA for the map: car/CNG/bus
via a self-hostable OSRM server (
GET /api/v1/rooms/eta/), cached 15 min, and a graceful fallback to the straight-line/MRT heuristics when routing is down (OSRM_ENABLED). - ClamAV virus scan for chat uploads — optional malware scan on
attachments; a positive detection rejects the file, an unreachable
scanner degrades to clean-by-default (type/size checks stay the gate).
Opt-in:
CLAMAV_ENABLED. - KYC automated pre-screening — every tenant verification submission is scored automatically (document parses, cross-account reuse via pHash, readable size, profile completeness, attempt history from the audit log) and the admin queue gets an approve/review recommendation + the reasons — the human decision stays the source of truth.
- react-router v7 — upgraded from v6 (fixes the last 2 moderate npm
audit findings;
npm auditis now clean).
Paid Listing Tiers (first revenue stream)
- Free → Featured (৳199/30d) → Premium (৳499/30d) promotion payments via SSLCommerz/bKash
- Server-side pricing, ownership + duplicate-tier guards, double-click race protection, premium-first search ordering
- Expired promotions auto-revert to Free (
expire_listingscommand + query-timeeffective_tier) - Dashboard Listings tab with Promote modal; gold/orange tier badges on cards
Roommate Matching — weighted scoring (budget/area/room-type/gender/lifestyle) with request/approve flow
Fraud Detection — 6-detector engine (duplicate title, copied description, price anomaly vs market percentiles, missing images, unverified owner, rapid spam) with auto-scan + admin review queueAuth & Trust
- Fresh login/register redesign (animated Dribbble-style auth page)
- Deep password strength meter — zxcvbn-ts engine: real entropy (
~10^Nguesses), common-password detection ("top-10 common password" warnings), 4-segment meter, live confirm-match indicator - HaveIBeenPwned breach check — k-anonymity lookup (only the first 5 chars of the SHA-1 hash leave the device); shows
⚠️ breached / ✓ safe / unknown status on the register formTwo-Factor Authentication (email OTP) - Password + one-time code — enabled per account from the Dashboard; enabling is email-verified: password first, then a code emailed to the address must be confirmed, so an account can never be locked behind an unreachable inbox
- 10 one-time recovery codes minted at enable (shown exactly once, stored hashed) — sign in with one if you lose email access; deleted when 2FA is disabled
- OTP codes stored hashed (SHA-256) in the DB; 10-minute TTL, 5-attempt lockout, 30s resend cooldown, stale challenges auto-invalidated on re-login
- Login returns a pending challenge (masked destination, e.g.
r***@rentora.com); tokens are only issued after the code verifies — no tokens leak at the password step
Passkeys (WebAuthn / FIDO2)
- Passwordless sign-in with a fingerprint, face, or device PIN —
py_webauthnserver-side,@simplewebauthn/browserclient-side - Conditional UI on the login form: passkeys surface in the browser's native autofill; a manual "Sign in with a passkey" button is the fallback
- Only public keys stored; sign counters tracked for clone/replay protection; 2FA-enabled accounts still get the email-OTP step after the passkey
- Register/revoke from the Dashboard → Security → Passkeys
- Sign in with username or email; duplicate-email registration now blocked (serializer + DB unique constraint) with a readable error message
- Already-logged-in users are redirected from
/authto their dashboard
Interactive Map (Phase 7)
- MapLibre GL JS map of Dhaka — OpenStreetMap tiles, key-free, with dark/light tile switching that follows the app theme
- Price marker pins — every listing is a tappable pin showing its price (
৳12k), coloured by tier (free orange / featured blue / premium amber) so promoted rooms pop exactly like the list - Marker clustering — with many listings in view, pins collapse into numbered cluster circles that show the room count + average rent (click one for a count/price-range popup, then it zooms in); toggle between Clustered and Pins modes
- Viewport sync — panning/zooming refetches rooms inside the visible
bbox(debounced 300ms), so the map and the room count always match what's on screen - Radius search — click a point on the map (or a university chip) and drag a slider to see rooms within 0.5–5 km, powered by the geo backend's
near_lat/near_lng+radius_km - Travel-time overlay — with a search point active, toggle Travel to draw walking isochrones (10/20/30 min bands, green → amber → red) so tenants see how far they can get on foot from a university, metro or office
- Street search + autocomplete — type a street, area or station ("gulshan", "mirpur road", "shahbagh") and pick a suggestion to fly there and start a radius search, powered by the curated Dhaka gazetteer with an OpenStreetMap Nominatim fallback (
/rooms/geocode/) so even streets outside the curated list geocode - Get Directions + travel-mode toggle — every room popup shows walking and driving ETA ("≈ 8 min walk · ≈ 2 min drive") plus a 🚶 Walk / 🚗 Drive / 🚇 Transit picker that opens Google Maps with the right route pre-filled (origin = your search point)
- Metro ETA in popups — each popup lists the nearest MRT station with distance + walking time ("🚇 Kawran Bazar MRT · 2.0 km · ≈ 27 min walk") from the backend's
proximityannotation - Area count chips — the current viewport's areas appear as tappable chips with live room counts ("Dhanmondi 3 · Mirpur 3") from
/rooms/summary/by_area; tap one to fly there and start a radius search - Metro route corridor — MRT Line 6 is drawn as a polyline through its stations (Uttara → Motijheel), visible with the Metro toggle or whenever the travel overlay is active; stations within a 30-minute walk of the search point get a highlighted ring
- Room-count API badge — the "N of M rooms in view" badge reads the authoritative server count (
/rooms/summary/— COUNT/AVG with the same geo filters), so it is never capped by list pagination - Distance markers — every listing in a radius search shows
formatDistance+ walking time ("1.2 km away · ≈ 16 min walk") in its map popup and the side list, from the backend'sdistance_kmannotation - Viewport bbox cache — the refetch bbox is quantized to ~100 m, so micro-pans hit the React Query cache instead of firing duplicate API calls
- Landmark layers — toggle universities 🎓, metro stations 🚇, hospitals 🏥, markets 🛒, parks 🌳, mosques 🕌 and bus terminals 🚌 on/off as map layers (from
/rooms/landmarks/); the everyday categories cluster into count bubbles at low zoom - Price heatmap — green → amber → red circles scaled by rent, so expensive areas are visible at a glance
- Map + list split view — a viewport-synced sidebar lists the rooms on screen (promoted first, then by price); on mobile it becomes a bottom sheet
- Tapping a pin opens the room popup → full RoomModal (booking, chat, fraud badge, AI price insight)
- Shareable map URLs — the current viewport (center + zoom + radius search) is live-synced to the URL (
/map?center=23.81,90.41&zoom=12&r=23.78,90.40,2.0), so you can copy the address and share an exact map view; the Share button copies the link, and opening a shared link restores the exact view, radius and area chips - Readable in both themes — dark tiles are the CARTO CDN; if it's unreachable the map auto-falls back to dimmed OSM tiles (street labels stay legible), and the travel overlay + legend are styled for light and dark
Intelligent Map (Phase 7 v2) — Rental Decision Intelligence
- AI Smart Map Search (🧠 "AI Map" button) — ask the map in Bangla, English or Banglish ("উত্তরায় ১২ হাজারের মধ্যে furnished room", "metro er kache room, Banani under 15k") and it parses the query into hard filters (area, budget, room type, amenities, metro proximity), flies to the matched area or metro station, updates the pins, and shows intent chips so you can see exactly what it understood — powered by the existing NL parser + gazetteer (
/rooms/map-intel/search/), no hallucinated listings - Metro Commute Score — every relevant listing carries a 0–100 transit-access score (walking time to the nearest MRT station, real curated station data) shown in the value-score chip
- Commute mode (🚇) — set a destination on the map (office / university / any point), and every visible listing gets a walking-time estimate ("🚶 8 min"); filter by max commute (15–60 min) — ETAs are honest straight-line estimates, labelled as such
- Best Value Score (⭐) — a transparent 0–100 server-side blend of price-fit vs the area market, amenities, listing quality, KYC verification, demand and metro access; each marker popup shows the score + transit factor, and the panel lists the top-value visible rooms
- Area Intelligence panel (🏛️ Areas) — tap an area chip for avg/median rent, listing counts, availability, 30-day demand (views/saves/bookings), metro access and price trend — all from real data,
—where none exists; select up to 3 areas for a side-by-side comparison table - Affordability map (💰 Budget) — drag a budget slider and see the real % of currently listed rooms per area that fit (green/amber/red bars) — a listing share, not an estimate
- Ideal Area ranking (⭐ Ideal Area) — budget + optional destination → the top areas ranked with the why ("100% of Mirpur listings fit your ৳10,000 budget · ~28 min commute (MRT estimate)")
- Destination pin — click the map to drop a teal destination flag for commute/ideal-area ranking; the pin is persisted in the shareable URL
- Everything real — no fabricated statistics: ETAs are labelled heuristics, transit ETA only exists along the MRT Line-6 corridor, and areas without data say "—"
See docs/INTELLIGENT_MAP.md (architecture) · docs/MAP_API.md (endpoints) · docs/MAP_SCORING.md (formulas).
Listing Location Picker (landlord)
- List a Room now opens a proper form with a map picker — click the map to pin the exact listing location (or "Use my location")
- Coordinates are stored as
lat/lng, powering the map view, geo search and price insight
KYC Verification + Verified Landlord Badge
- Identity document upload — landlords upload a NID or passport (image/PDF, 5 MB cap) from Dashboard → KYC (
KycCard); uploads are stored server-side and served through an auth-gated endpoint (owner/admin only — the public media URL can never leak a document, and other users get a 404 so no existence leak) - Admin review panel — pending applications queue (
GET /users/kyc/pending/) with approve/reject; a decision flipsnid_verified, syncs every listing badge via signals, resolves the pending documents, writes an audit-log entry (kyc.approved/kyc.rejected) and notifies the landlord — all inside onetransaction.atomic()block - KYC audit trail — Dashboard → KYC → History lists every decision (who, when, note) straight from the append-only audit log
- Verified badge everywhere — RoomCard pill, RoomModal, Roommates match cards, and Chat (shield next to a verified participant's name); verified-first ranking inside each tier
- "Verified landlords only" filter — one toggle on the Rooms page (
?verified=true) narrows results to KYC-approved owners - E2E coverage — upload → 403 for non-admin → queue → approve (badge flip + audit + notification + fraud signal clears) → reject with note → reject → re-upload → approve full loop (the landlord sees the reviewer's note on their rejected doc, re-submits, and the badge finally lands — the audit trail tells the whole story) → revoke flips back → privacy (404 for strangers) → file-type guard: 12 KYC tests
- Rejection UX — the dashboard KycCard shows a "Why it was rejected" banner with the reviewer's note (e.g. "Blurry scan — please re-upload") plus the upload form, so the landlord knows exactly what to fix before re-submitting
- Rejection email — a rejection also sends a branded transactional email (
kyc_rejectedtemplate) with the reviewer's note and a direct re-upload CTA that deep-links to the dashboard KYC tab, so the landlord can fix and resubmit without hunting through the app - KYC review SLA stats — the admin panel now opens with a queue-health strip: pending applications (with the oldest-waiting age), average review time (all-time + this week), and a 7-day decision trend (
▲ +N / ▼ -Nvs last week), all fromGET /users/kyc/sla/(admin-only) - SLA breach badges — when a breach fires the strip grows red alert chips ("Application waiting >48h" / "Decisions down vs last week"), matching the flags the daily beat alert emails about — dashboard and alerts never disagree (same thresholds)
- 30-day decision trend chart — the admin History tab now opens with a lightweight dependency-free SVG chart: daily decision counts (bars) + average review hours (line) over the last 30 days, bucketed server-side with
TruncDate
Engineering
- Coverage history per branch — every PR and main push appends its own
history-<branch>.csv+ SVG chart to thecoverage-historybranch (viewableindex.htmllinking all branches) - 528 automated tests (334 backend + 194 frontend) · coverage gates (BE ≥50%, FE ≥55%)
- Ruff + ESLint + Prettier with husky/lint-staged pre-commit hooks
- GitHub Actions CI (backend, frontend, live API contract check, frontend schema contract (TS types vs OpenAPI), schema-drift PR comment, lint, coverage-summary PR comment, per-branch coverage history)
- Route-level code splitting (React.lazy) — smaller bundles
Search & Discovery (Phase 11) — ✨ AI Smart Search
- AI Search toggle — the Rooms page's search bar grows a gradient ✨ AI Search button; flip it on and the box accepts natural language: "১০ হাজার এর মধ্যে uttara student room" is understood as budget ≤ ৳10,000 in Uttara (and "জুলাই move-in" as a July move-in date)
- Bangla + English natural-language parser (
rooms/nl_query.py) — Bangla digits (০-৯), number words (দশ/বিশ/ত্রিশ… with হাজার/লাখ/কোটি multipliers — "দশ হাজার" → ৳10,000), ৳/টাকা/tk/taka, area names in both scripts (Uttara and উত্তরা, Dhanmondi and ধানমন্ডি — from the gazetteer's new Bangla aliases), room-type/gender words and month names in both scripts; the parsed budget/area/type/gender become real filters, and the list response carries annl_parsedobject - "AI understood" chips — under the search bar the backend's interpretation renders as tappable-looking pills (
Budget ≤ ৳10,000·Uttara·move-in July) so tenants see exactly what was understood - Hybrid neural semantic ranking — smart search now blends two relevance legs with configurable weights (
SEMANTIC_SEARCH_WEIGHT=0.7neural +TFIDF_SEARCH_WEIGHT=0.3lexical). The neural leg uses pluggable embeddings (rooms/embedding_service.py): a zero-dependency bilingual synonym-hash provider runs out of the box (no heavy deps — "affordable student room" finds "কম বাজেটের শিক্ষার্থীদের থাকার রুম" in both query directions), and installing the optionalsentence-transformerspackage transparently upgrades it to real multilingual neural embeddings. If embeddings are unavailable, ranking degrades to the TF-IDF/LSA leg, then to keyword search — search never breaks - Typo tolerance — smart search resolves same-script typos against a bounded area gazetteer:
mirpore/মিরপূরstill find Mirpur,Dhanmondhifinds Dhanmondi,uttrafinds Uttara (FUZZY_SEARCH_ENABLED) - Bangla/English area aliases — a single alias table (
rooms/area_aliases.py) resolves every spelling of a place —ধানমন্ডি,ধানমণ্ডি,Dhanmondi,Dhanmondhi,ধানমন্ডি ২৭,mirpur 10,উত্তরা সেক্টর ১০— to its canonical area, shared by the NL parser and map gazetteer (AREA_ALIAS_ENABLED) - Personalized search re-ranking — for signed-in tenants, smart-search results are re-ranked within the relevant pool by the user's preference profile (preferred area/type/budget/amenities — reused from the recommendation engine, no duplicated logic); cold-start users get plain relevance ranking and hard filters (budget/area) always win (
PERSONALIZED_SEARCH_ENABLED,PERSONALIZATION_WEIGHT=0.15) - Price-anomaly badge — room cards show a transparent price-vs-market chip (
↑ 25% above market) computed from the existing fair-price prediction model, trained once per request and only rendered when the prediction is confident and the gap clearsPRICE_ANOMALY_THRESHOLD(20%) - Debug ranking metadata —
?debug_rank=1(orDEBUG=true) attachesrank_meta(semantic/lexical/personalization/final scores per room) to the list response; never exposed to normal users - Personal ranking boost — for signed-in tenants the default browse order floats rooms they recently viewed or wishlisted to the top (30-day window), layered under the paid-tier/verified ranking
- Look-Alike Rooms (visual search) — every RoomModal now shows a "Look-Alike Rooms" strip: rooms whose primary photo looks like the current one, via 64-bit perceptual hashes (pHash) computed with Pillow and cached in a new
RoomImageHashtable (mtime-keyed, so replaced photos re-hash automatically);GET /rooms/{id}/similar-images/ - Dhaka coverage expanded — the listing
Areachoices now span 20 areas (Uttara, Tejgaon, Badda, Rampura, Banasree, Khilgaon, Motijheel, Old Dhaka, Bashundhara, Lalmatia, Shyamoli, Savar, Keraniganj, Tongi + the original 6) and the map gazetteer gained 40+ new streets/roads (Panthapath, Bailey Road, Hatirjheel, Badda Link Road, Khilgaon Flyover, Uttara Sectors 10/12/14, Gulshan 1/2 circles, Jashimuddin Avenue …) plus 9 more universities (Jagannath, Dhaka Medical College, AUST, DIU, Stamford, UIU …) — all searchable from the map box and the NL parser - Bug fixes along the way — the room list now sends the backend's
qsearch param correctly (params.search→params.q), and the API client no longer yanks anonymous visitors to/authwhen a public endpoint 401s (the bounce is now reserved for sessions that actually went stale) — regression-tested
Core AI & Fraud Intelligence (Phase 11++) — Rentora Copilot, AI pricing v2, duplicate-image fraud
- 🤖 Rentora Copilot (
COPILOT_ENABLED) — a floating conversational assistant (bottom-right, every page): ask in Bangla, English or Banglish ("Uttara-তে ১০ হাজারের মধ্যে furnished student room চাই") and it searches the live listings. Hybrid and free: intent parsing (reusing the NL parser + an amenity/property word table) feeds the existing search/ranking pipeline, and the reply is generated over the retrieved rows only — it can never hallucinate a room, price or amenity, and no LLM is required. Follow-up turns keep context ("শুধু furnished দেখাও" retains Uttara + budget via a session_id), listing cards open the full RoomModal, quick-reply chips are backend-generated (POST /api/v1/copilot/chat/, 60/hr throttle). Seedocs/RENTORA_COPILOT.md - 🏷️ AI pricing suggestion v2 (
GET /pricing/suggestion/:id/, owner/admin) — the fair-price model upgraded with demand: recommended price + range (rounded to ৳500), a 0–100 demand score from real engagement (views vs area peers, wishlist saves, booking requests, area heat), estimated time-to-rent from actual booking history (never fabricated — "Insufficient historical data" when there aren't 5 samples), composite confidence, and explainable reasons ("Similar Mirpur singles average ৳8,500"). Cached per room + market snapshot. Dashboard → Insights → AI Price expands the suggestion card with a Use ৳12,500 button — the landlord always decides; nothing changes automatically. Seedocs/AI_PRICING_V2.md - 🖼️ Cross-listing duplicate-image fraud detection (
DUPLICATE_IMAGE_FRAUD_ENABLED) — the pHash pipeline (already powering look-alike rooms) now feeds a 7th fraud detector: the same photo re-used across listings is flagged with contextual severity (same-owner agency posts → low; different owners → medium; different owner and area, or 3+ matches → high). Hex-prefix pre-filtering keeps scans from N×N; same-listing galleries and blank images are never flagged; the signal feeds the existing fraud score → search ranking, and the admin Fraud Operations panel shows matched-listing chips + similarity %. Seedocs/DUPLICATE_IMAGE_FRAUD.md
Listing Intelligence (Phase 11+) — voice search, AI saved-search matching, listing quality, fraud-aware ranking
- 🎤 Bangla voice search — the search bar grows a microphone button (
VOICE_SEARCH_ENABLED): the browser's Web Speech API transcribes Bangla / Banglish / English naturally ("উত্তরা ১০ হাজারের মধ্যে রুম" →?q=), and the transcript flows straight into the existing NL parser + semantic ranking — no new NLP pipeline, no audio ever stored or uploaded (only the transcript). Unsupported browsers hide the button; permission-denied shows a friendly hint; text search always works (useVoiceSearchhook, states: idle/listening/processing/denied/unsupported/error) - 🧠 AI saved-search matcher (
SAVED_SEARCH_AI_MATCHING_ENABLED) — saved-search alerts upgraded from "new listing" to "Highly relevant room found in Uttara" with why it matched reasons (✓ matches your area ✓ within budget ✓ similar to rooms you viewed). Two-stage pipeline: hard filters always gate first (area/budget/type/gender — a Dhanmondi room can never match a Uttara search), then a weighted relevance score (area/price/room-type/semantic/preference/quality, weights +SAVED_SEARCH_MATCH_THRESHOLD=0.75configurable). Alerts fire in-app from a room create/price-change event task and the daily digest, deduplicated by a cooldown (SAVED_SEARCH_COOLDOWN_HOURS); price-drop alerts (≥PRICE_DROP_NOTIFICATION_THRESHOLD10%) ride on the newRoomPriceHistorytable written by a post-save signal - ✨ Listing quality score (
LISTING_QUALITY_SCORE_ENABLED) — every listing gets a transparent 0–100 completeness score (basic info 20 / description 20 / photos 20 / location 15 / amenities 15 / pricing 10 — weights configurable) with actionable suggestions ("Add 3 more photos", "Description is too short…", "Add nearby landmark information"). Shown as a quality chip on the room detail page and a per-listing Quality column in the landlord Insights dashboard with a tap-for-suggestions popover, plus an Avg Listing Quality card on the landlord overview. It's not a valuation and not a fraud score — every point is explainable - 🛡️ Fraud-aware search ranking (
FRAUD_AWARE_RANKING_ENABLED) — smart-search results are demoted by the existing fraud engine's risk score (one query, no re-scan): high-risk listings sink below clean ones of equal relevance (FRAUD_RANKING_PENALTY_WEIGHT=0.20), and critical-risk handling follows the existing moderation flow — ranking never hides or deletes a listing. Risk never overrides explicit user intent (hard filters → relevance → personalization → quality → fraud), and internal detector evidence is never exposed to normal users (admin dashboard unchanged) - Search pipeline now: query → normalization → area-alias expansion → hard filters → lexical + semantic legs → personalization → quality + fraud secondary signals → final ranking → API response
- Copilot retrieval reuses the same pipeline — hard filters (budget/area/type/gender/amenities) gate first, then hybrid ranking — so a Copilot answer and the Rooms page agree by construction
Tracked like a product backlog — every shipped phase is checked off.
| Phase | Scope | Status |
|---|---|---|
| 1–2 | React prototype with mock data | ✅ Shipped |
| 2.5 | Frontend refactor — Vite, TS strict, Tailwind, Zustand, React Query, shadcn/ui | ✅ Shipped |
| 3 | Django backend — 10+ apps, JWT auth, full REST API, frontend integration | ✅ Shipped |
| 4 | Real-time chat (Django Channels, typing, read receipts, file upload) + real-time notifications | ✅ Shipped |
| 5 | Payments — SSLCommerz + bKash, refunds, PDF receipts, invoices, security deposits, webhook audit | ✅ Shipped |
| 6 | AI — recommendation engine (content/collaborative/hybrid) + price insight + fair-price prediction | ✅ Shipped |
| Bonus | Roommate matching (profile + scoring + request flow) | ✅ Shipped |
| Bonus | Fraud engine (6 detectors, auto-scan, review queue) | ✅ Shipped |
| Bonus | Paid listing tiers (Free/Featured/Premium monetization) | ✅ Shipped |
| Bonus | Two-factor authentication (email OTP, password-gated enable) | ✅ Shipped |
| Bonus | KYC verification + verified-landlord badge + document upload + audit trail | ✅ Shipped |
| Bonus | 2FA recovery codes (10 one-time backups) + email-verified enable | ✅ Shipped |
| Bonus | Passkeys / WebAuthn (passwordless login, conditional UI) | ✅ Shipped |
| Bonus | Geo backend (bbox / radius / landmark queries) | ✅ Shipped |
| 7 | Map (MapLibre GL, clustering, split view, radius + travel overlay, street search, metro routes, room-count API, directions + metro ETA + area chips) | ✅ Shipped |
| 8 | Docker Compose + production deployment + HTTPS | ⏳ Next — CI/CD done |
| 9 | Reliability & observability — Sentry, JSON logs, Celery + beat, branded emails, audit log, backups, KYC SLA alerts + trend chart | ✅ Shipped |
| 10 | Growth & personalization — browser push, search v2 (full-text + saved searches), similar-rooms AI, referral program, wishlist sharing, landlord insights, reviews v2 | ✅ Shipped |
| 11 | Search & Discovery v2 — ✨ AI smart search (Bangla+English NL parser, semantic ranking, visual search), Dhaka expansion | ✅ Shipped |
| 11+ | Listing Intelligence — 🎤 Bangla voice search, 🧠 AI saved-search matcher + price-drop alerts, ✨ listing quality score, 🛡️ fraud-aware ranking | ✅ Shipped |
| 11++ | Core AI & Fraud — 🤖 Rentora Copilot, 🏷️ AI pricing suggestion v2 (demand/time-to-rent), 🖼️ cross-listing duplicate-image fraud detection | ✅ Shipped |
| 7 v2 | Intelligent Map — 🧠 AI map search, 🚇 metro commute score + commute mode, ⭐ best-value scores, 🏛️ area intelligence + comparison, 💰 affordability map, ideal-area ranking | ✅ Shipped |
| 7 v3 | Map Intelligence v3 — 🌙 dark-map fix + 🌑 layer contrast QA, 👆 interactive university/metro/heatmap/isochrone clicks, 🔗 map↔list sync, 🔗 room deep links, 🏙️ structured Dhaka hierarchy + area boundary polygons, 🏥 expanded landmark layer (hospitals/markets/parks/mosques/bus terminals, clustered) | ✅ Shipped |
| 12 P0 | Progressive Web App — 📱 installable manifest + maskable icons, native install CTA, standalone mode, safe SW caching, update + offline UX, shortcuts | ✅ Shipped |
| 12 P1 | Offline & polish — 🔌 offline search over cached public listings, background sync (offline action replay), periodic refresh, splash screens, dark icon, iOS install hint, Lighthouse audit | ✅ Shipped |
| 12 | Trust & Safety V2 — two-sided marketplace integrity: 🪪 tenant KYC + verified-tenant badge, 🛡️ chat safety engine, 🚩 report/block, 🖼️ photo + review moderation, ⚖️ disputes + deposit protection, 🎛️ admin Trust & Safety Operations Center + audit trail | ✅ Shipped |
| 12.6 | Tier-1 Quick Wins — 💬 chat message search + edit/delete (audited), 📧 saved-search email digest, 🚦 report rate-limit + duplicate guard, ⚡ semantic search cache, 🛡️ CSP headers + security.txt + dependency bump audit | ✅ Shipped |
| 12.7 | Tier-2 Upgrades — 🧠 AI chat-safety classifier (learned layer, human fallback), 📊 self-hosted analytics + conversion funnel, 🖼️ photo manipulation/watermark detection (ELA), 🗺️ OSRM road-network ETA, 🦠 ClamAV upload scan, 🪪 KYC auto pre-screening, ⬆️ react-router v7 | ✅ Shipped |
| 12.8 | Tier-3 Upgrades — 🤖 RAG Copilot (listing-grounded Q&A, zero hallucination), 🌐 full EN⇄BN UI toggle, 🧠 production-grade neural embeddings (disk-persisted matrix + prebuild command), 🧪 E2E expansion (trust-flow + map), 👤 tenant behavioral trust signals (completed bookings) | ✅ Shipped |
| 12.9 | Tier-4 Upgrades — 🤝 AI Rental Advisor, 💬 AI Negotiation Assistant, 📄 AI Agreement Checker, 🏠 Landlord Copilot, 📊 AI Property Comparison, 📈 Demand Forecasting, 🔔 Smart AI Alerts, 🧠 hosted neural embeddings (HF endpoint), 🪪 automated KYC pre-verification, 🧪 browser-level Playwright E2E | ✅ Shipped |
| 12.10 | Tier-5 Upgrades — 📈 conversion funnel fully wired (booking_confirmed + payment_completed server-side), 🖼️ photo forensics v2 (text-overlay + tiled-watermark detection), 💹 per-listing price recommendation (demand forecast + market + interest), 👁️ Copilot image understanding (statistical photo answers), ✍️ AI listing draft (one-click title/description/amenities) | ✅ Shipped |
| 13 | Reach — 📱 SMS OTP phone sign-in (BD market, gateway-gated), 🟢 WhatsApp listing share + AI share summary, 🗺️ per-area SEO landing pages + sitemap, ⚡ Lighthouse performance gate in CI | ✅ Shipped |
| 14 | AI v3 Vision & Content — 👁️ photo intelligence (caption/palette/observations from actual photos), ✍️ AI draft title + description from photos, 🏷️ suggested amenity tags (review-then-apply), 📷 AI image search ("upload a photo, find rooms that look like it") with match scores | ✅ Shipped |
| 15 | Monetization 2.0 — 💳 subscriptions + entitlements (landlord SaaS), 🧾 idempotent revenue ledger + commission engine, 🏢 corporate housing (accounts / bulk booking / invoices), 🏅 verified broker network (attribution / payouts), 🛍️ add-on services marketplace (orders + AI cross-sell), 🛡️ insurance & credit partnerships, 🎛️ admin revenue & payout centre | ✅ Shipped |
| 16 | Hardening & Scale — 🧠 embeddings + pgvector (vendor-guarded), 🚩 feature flags + A/B experiments, 🖼️ image pipeline/CDN (WebP variants, private storage), 🔴 Redis hardening (leases, locks, timeouts), ⚡ rate limiting + abuse prevention, ⏱️ Celery reliability (retry, ack-late, time limits), 🏥 /health/ liveness, 📋 X-Request-ID correlation |
✅ Shipped |
| 17 | Graph & Deep Trust — 🕸️ scam-network graph (PostgreSQL nodes/edges, community detection), 🪪 KYC liveness + face-match (pluggable providers), 📷 photo-geo authenticity (GPS mismatch), 🕵️ fake-review detection (trust scoring + anomalies), 📊 model drift monitoring (metrics + retrain requests), 🔐 PII masking + privacy layer, 🧩 shared provider abstraction (BaseProvider/Registry) | ✅ Shipped |
| 18.1 | AI Intelligence Foundation — 🧠 AI feature registry (central registry + provider tracking), 📊 execution telemetry (latency/tokens/cost/confidence per request), 🏥 provider health monitoring (p95/p99 latency, success rates, auto-degradation), 💰 cost estimation engine (OpenAI + Anthropic pricing), 🔌 TelemetryMixin (drop-in for BaseProvider), 🎛️ admin API (7 endpoints, staff-only) | ✅ Shipped |
| 18.2 | AI Intelligence Foundation — 📝 prompt registry (versioned templates, activate/deactivate/rollback), 🔗 feature flag integration (is_feature_available checks registry + Django flags), 🌱 register_ai_features seeds 30 real features, 🎛️ admin API expanded to 18 endpoints |
✅ Shipped |
| 18.3 | AI Evaluation Framework — 📏 evaluation metrics (deterministic/heuristic/LLM-judge), 📊 golden datasets (versioned, publishable), 🔬 evaluator abstraction (26 built-in: search/classification/fraud/LLM/general/prediction), 🧪 evaluation runs (async Celery, per-case results), 📈 model/prompt comparison, 🚨 regression detection (threshold-based), 🎛️ admin API (17 eval endpoints) | ✅ Shipped |
For Tenants
- Browse and search verified room listings across Dhaka
- AI-powered room recommendations based on budget, area, and preferences
- Advanced filters (area, type, price range, amenities, gender preference)
- Geo search — filter by map viewport (
bbox), radius around a point, or proximity to landmarks/metro stations - Interactive map (MapLibre GL) — price pins, radius search, university/metro layers, price heatmap
- Wishlist rooms for later
- Book rooms with one click
- Real-time chat with landlords (WebSocket — typing, read receipts, file upload)
- Roommate matching — find compatible flatmates by budget, area, lifestyle, and gender preference
- Tenant identity verification — verify once with a NID/passport and carry the ✓ Identity Verified badge (identity only — never a behavioral or financial guarantee)
- Chat safety — every message is screened for payment-redirect scams, phishing links and impersonation; risky messages show warnings and blocked ones are replaced with a safety notice
- Report & block — report a user or a specific message (scam, harassment, fake listing, payment fraud…) and block/unblock to close a conversation both ways
- Dispute resolution — open a structured dispute on an approved booking (deposit, property condition, cancellation…) with evidence, admin review and a clear outcome
- Dashboard with booking stats and notifications
For Landlords
- Create and manage room listings with multiple images
- Receive booking requests with approve/reject workflow
- Get notified on new bookings and reviews
- Fraud protection — every listing is auto-scanned on creation; flagged listings show an "under review" badge
- Paid listing tiers — promote a listing to Featured (৳199/30 days) or Premium (৳499/30 days) via SSLCommerz/bKash to rank higher in search and show a badge; expired promotions auto-revert to Free
- KYC verification — verified landlords carry a trust badge (RoomCard, RoomModal, Roommates, Chat) and rank first; tenants can filter to verified owners only
- Verified tenants in chat — identity-verified tenants carry the ✓ badge in chat, booking requests and roommate matches, so you know who's inquiring
- Report & dispute tools — report problem users/messages and respond to booking disputes with evidence before a resolution is decided
- Dashboard with revenue stats, ratings, listing analytics, and fraud risk cards with one-click re-scan
Platform Features
- JWT authentication (register/login/refresh/logout) with unique-email enforcement
- Paid listing tiers (monetization) with server-side pricing and premium-first search ordering
- Real-time notifications (booking updates, reviews, roommate requests, fraud flags)
- Review system with verified stay badges — reviews and photos are auto-moderated (spam, duplicate-image, contact harvesting) with an admin approval queue
- 6-detector fraud engine
- Trust & Safety Operations Center — unified admin console (tenant KYC queue, chat-safety feed, report tickets, photo/review moderation, disputes + deposit decisions) with a read-only audit trail
- Responsive design (mobile, tablet, desktop) + dark mode
- API documentation (Swagger UI + ReDoc)
| Technology | Purpose |
|---|---|
| React 18 | UI framework |
| TypeScript (strict) | Type safety |
| Vite | Build tool |
| TailwindCSS v4 | Styling |
| shadcn/ui | Component library |
| React Router v6 | Client-side routing |
| Zustand | Client state management |
| TanStack Query | Server state + caching |
| Axios | HTTP client with interceptors |
| React Hook Form + Zod | Form validation |
| Motion | Entrance/exit animation |
| MapLibre GL JS | Interactive map (markers, layers, heatmap) |
| zxcvbn-ts | Password entropy + strength |
| Pwned Passwords (HIBP) | k-anonymity breach lookup |
| Sonner | Toast notifications |
| Vitest | Unit tests + coverage |
| @simplewebauthn/browser | Passkey ceremony client |
| Technology | Purpose |
|---|---|
| Django 5.2 | Web framework |
| Django REST Framework | REST API |
| Django Channels | WebSocket support |
| Daphne | ASGI server |
| SimpleJWT | JWT authentication |
| dj-rest-auth + django-allauth | Auth endpoints |
| django-filter | API filtering |
| drf-spectacular | OpenAPI docs |
| bleach | Input sanitization |
| difflib | Similarity detection (fraud engine) |
| PostgreSQL 16 | Production database |
| SQLite | Development database |
| Redis | Channel layer + caching + Celery broker |
| Celery | Async task queue + beat scheduler |
| Sentry (sentry-sdk) | Error tracking (backend + frontend) |
| py_webauthn | WebAuthn/FIDO2 server-side (passkeys) |
| scikit-learn | TF-IDF + LSA semantic search |
| sentence-transformers (optional) | Real multilingual neural embeddings (upgrades the built-in lite provider) |
| Pillow (pHash) | Visual similarity (look-alike rooms) |
| pywebpush | Browser push notifications (VAPID) |
| pytest / unittest | Backend tests |
┌──────────────────────────────────────────────────────────────┐
│ Frontend (React SPA) │
│ Pages ── hooks (TanStack Query) ── services ── Axios API │
│ Zustand stores ── WebSocket client ── service worker (push) │
│ MapLibre GL (map) · WebAuthn (passkeys) · zxcvbn (strength) │
└───────────────┬──────────────────────────────┬────────────────┘
│ HTTP /api/v1/* │ WS /ws/chat/*
┌───────────────▼──────────────────────────────▼────────────────┐
│ Django (ASGI — Daphne) │
│ ┌────────────┐ ┌────────────┐ ┌────────────────────────────┐ │
│ │ JWT Auth │ │ REST apps │ │ Channels consumer (chat) │ │
│ │ 2FA + │ │ rooms, │ │ + presence + notifications │ │
│ │ passkeys │ │ bookings, │ └────────────────────────────┘ │
│ │ (WebAuthn) │ │ payments, │ ┌────────────────────────────┐ │
│ └────────────┘ │ roommates, │ │ Fraud engine (6 detectors)│ │
│ ┌────────────┐ │ fraud, AI, │ └────────────────────────────┘ │
│ │ Exception │ │ saved- │ ┌────────────────────────────┐ │
│ │ envelope │ │ searches… │ │ Hybrid semantic search │ │
│ └────────────┘ └────────────┘ │ (embeddings + TF-IDF/LSA) · │ │
│ ┌────────────┐ │ NL parser · aliases · pHash │ │
│ │ Audit log │ └────────────────────────────┘ │
│ │ (append- │ ┌──────────────────────────────────────────┐ │
│ │ (append- │ │ Celery + Beat (push, alerts, re-scan) │ │
│ │ only) │ └──────────────────────────────────────────┘ │
│ └────────────┘ Sentry (errors) · JSON logs · email templates│
└───────────────┬──────────────────────────────────────────────┘
│ ORM / cache / channel layer
┌───────▼──────────┐ ┌──────────┐ ┌──────────────┐
│ SQLite (dev) / │ │ Redis │ │ SSLCommerz / │
│ PostgreSQL 16 │ │ (cache, │ │ bKash gateways│
└──────────────────┘ │ channel) │ └──────────────┘
└──────────┘
Rentora/
├── frontend/ # React SPA
│ ├── src/
│ │ ├── components/ # UI components (Navbar, RoomCard, ChatWindow, PromoteModal, TierBadge…)
│ │ │ └── ui/ # shadcn/ui primitives
│ │ ├── pages/ # Route pages (Home, Rooms, Map, Chat, Dashboard, Roommates, Auth)
│ │ ├── services/ # API service layer (auth, rooms, bookings, roommates, fraud, payments…)
│ │ ├── hooks/ # TanStack Query hooks
│ │ ├── stores/ # Zustand stores (ui, wishlist, notifications)
│ │ ├── context/ # React context (AppContext for auth)
│ │ ├── types/ # TypeScript type definitions
│ │ ├── config/ # Environment config
│ │ └── styles/ # TailwindCSS config + global styles
│ ├── vite.config.ts
│ ├── tsconfig.json
│ └── package.json
│
├── backend/ # Django REST API
│ ├── config/ # Project config (settings, urls, asgi, exceptions, middleware)
│ │ └── settings/ # Split settings (base, dev, prod)
│ ├── users/ # Custom User model + auth (unique email enforced)
│ ├── rooms/ # Room listings + images + geo queries + listing tiers
│ ├── bookings/ # Bookings + Reviews + signals
│ ├── wishlist/ # Wishlist toggle
│ ├── notifications/ # Auto-notifications + API
│ ├── dashboard/ # Aggregated stats endpoint
│ ├── chat/ # Real-time chat (Channels, WebSocket, presence)
│ ├── payments/ # SSLCommerz + bKash, refunds, invoices, receipts, tier upgrades
│ ├── recommendations/ # Content-based + collaborative + hybrid engine
│ ├── pricing/ # Market stats + price insight + fair-price prediction
│ ├── roommates/ # Roommate profiles + weighted matching algorithm
│ ├── fraud/ # 6-detector fraud engine + auto-scan + review queue
│ ├── manage.py
│ └── requirements.txt
│
└── docs/ # Documentation + screenshot tooling
Quality is enforced in CI and at commit time — style or coverage drift fails the pipeline automatically.
| Suite | Count | Gate |
|---|---|---|
| Backend (Django) | 716 | ✅ passing · coverage ≥ 50% lines |
| Frontend (Vitest) | 342 | ✅ passing · coverage ≥ 55% lines |
# Backend
cd backend && venv/Scripts/python.exe -m coverage run manage.py test && venv/Scripts/python.exe -m coverage report
# Frontend
cd frontend && npx vitest run --coverage# Backend (ruff)
cd backend
venv/Scripts/python.exe -m ruff check . # lint
venv/Scripts/python.exe -m ruff check --fix . # auto-fix
venv/Scripts/python.exe -m ruff format . # format
venv/Scripts/python.exe -m ruff format --check . # verify
# Frontend (ESLint + Prettier)
cd frontend
npm run lint
npm run format
npm run format:checkInstalled automatically by npm install (prepare script). On every commit it runs only on staged files:
| Staged file | Runs |
|---|---|
backend/**/*.py |
ruff check --fix + ruff format |
frontend/**/*.{ts,tsx} |
prettier --write + eslint |
frontend/**/*.{css,json,md,html} |
prettier --write |
If a check fails, the commit is blocked — fix and commit again (bypass with git commit --no-verify only when intentional).
| Workflow | Job | Runs on |
|---|---|---|
ci.yml |
Backend — Django tests + coverage gate | every push / PR |
ci.yml |
Frontend — Vitest + coverage + npm run build |
every push / PR |
ci.yml |
API contract — boots a server + runs the live endpoint suite vs the docs reference (status codes + deep JSON schema + request-body contracts + OpenAPI path cross-check; response/request contracts are auto-generated from the live OpenAPI schema at runtime — docs/tools/api-verify.py) |
every push / PR |
ci.yml |
Frontend contract — regenerates TS types from the live OpenAPI schema (openapi-typescript) and typechecks the hand-written wire types (services/mappers.ts) against them via src/lib/schemaContract.ts — a backend field rename/removal/type change fails the PR |
every push / PR |
ci.yml |
Schema drift — diffs the PR head's OpenAPI schema against the base branch and posts a sticky PR comment listing every endpoint/field contract change (docs/tools/schema-drift.py; doc-only changes ignored) |
PRs |
security.yml |
Security — pip-audit (dependency advisories, hard-fail), Bandit (MEDIUM+ static analysis, hard-fail), Django check --deploy, security regression tests (upload validation / admin-only fraud / IDOR / KYC ownership), npm audit --audit-level=high (hard-fail) and a gitleaks secret scan — all with least-privilege contents: read |
every push / PR |
ci.yml |
Lint — ruff + ESLint + Prettier | every push / PR |
coverage-summary.yml |
Posts a coverage PR comment (badge + file-level detail) | PRs |
ci.yml coverage-history job |
Appends per-branch coverage history (history-<branch>.csv + SVG chart) to the coverage-history branch |
pushes to main and PRs (same-repo; fork PRs skip) |
git clone https://github.com/SadmaFaahiim/Rentora.git && cd Rentora
# Backend → http://localhost:8000
cd backend
python -m venv venv && venv\Scripts\activate # (Linux/macOS: source venv/bin/activate)
pip install -r requirements.txt
python manage.py migrate
python manage.py seed_rooms # 20+ rooms + demo landlords (password: demo12345)
python manage.py runserver
# Frontend → http://localhost:3000 (new terminal)
cd ../frontend
npm install
npm run dev💡
seed_roomsalso creates the demo users below — sign in with any username +demo12345. No.envfiles are required; sensible defaults work out of the box.Optional — real neural embeddings: smart search works out of the box with the built-in zero-dependency lite provider. To upgrade to true multilingual transformer embeddings, install the optional package:
pip install sentence-transformers(a multi-hundred-MB download incl. PyTorch) — the app detects it automatically and usesSEMANTIC_EMBEDDING_MODEL(default:sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2).
- Python 3.11+
- Node.js 18+
- Git
cd backend
# Create virtual environment
python -m venv venv
# Activate (Windows)
venv\Scripts\activate
# Activate (macOS/Linux)
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Run migrations
python manage.py migrate
# Seed sample data (rooms + demo landlords)
python manage.py seed_rooms
# Scan all rooms with the fraud engine (optional)
python manage.py scan_rooms
# Create admin user
python manage.py createsuperuser
# Start server
python manage.py runserver
# Backup the database (SQLite copy or pg_dump; prunes old backups)
python ../scripts/backup_db.py --keep 14Backend runs at http://localhost:8000
Celery (optional, async mode) — with no broker configured, tasks run eagerly
(synchronously) so nothing extra is needed locally. To run a real worker + beat
schedule, start Redis and set CELERY_BROKER_URL=redis://localhost:6379/0 in
backend/.env, then:
celery -A config worker -l info
celery -A config beat -l infoError tracking — set SENTRY_DSN (backend .env) and VITE_SENTRY_DSN
(frontend .env) to enable Sentry; leaving them unset keeps everything working
with no events sent. See docs/ops/backup-restore.md for the backup/restore
runbook.
cd frontend
# Install dependencies
npm install
# Create .env file
echo "VITE_API_BASE_URL=http://localhost:8000/api/v1" > .env
# Start dev server
npm run devFrontend runs at http://localhost:3000
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/auth/register/ |
Public | Register (email must be unique) |
| POST | /api/v1/auth/login/ |
Public | Login with email or username (returns JWT) |
| POST | /api/v1/auth/logout/ |
Auth | Logout (blacklist token) |
| POST | /api/v1/auth/token/refresh/ |
Public | Refresh access token |
| GET | /api/v1/auth/user/ |
Auth | Get current user profile |
| PATCH | /api/v1/auth/user/ |
Auth | Update profile |
| POST | /api/v1/auth/otp/verify/ |
Public | Finish 2FA login: exchange (challenge, code) for JWTs; pass recovery_code instead to use a backup code |
| POST | /api/v1/auth/otp/resend/ |
Public | Re-send the one-time code (cooldown-guarded) |
| POST | /api/v1/auth/otp/toggle/ |
Auth | Disable 2FA, or begin enabling (password → emailed code) |
| POST | /api/v1/auth/otp/confirm-enable/ |
Auth | Confirm the emailed code → 2FA on + one-time recovery codes |
| POST | /api/v1/auth/passkey/register/begin/ |
Auth | Registration options for the browser ceremony |
| POST | /api/v1/auth/passkey/register/complete/ |
Auth | Verify + store the new passkey (public key only) |
| POST | /api/v1/auth/passkey/login/begin/ |
Public | Authentication options + challenge_id (conditional UI) |
| POST | /api/v1/auth/passkey/login/complete/ |
Public | Verify the assertion → JWTs (or pending OTP for 2FA) |
| POST | /api/v1/auth/sms/request/ |
Public | Request an SMS OTP for a phone number (503 while SMS is disabled) |
| POST | /api/v1/auth/sms/verify/ |
Public | Verify the SMS code → JWTs (new numbers auto-register) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/rooms/ |
Public | List rooms (filter/search/sort/geo/tier ordering) |
| GET | /api/v1/rooms/:id/ |
Public | Room detail |
| POST | /api/v1/rooms/ |
Auth | Create listing |
| PUT/PATCH | /api/v1/rooms/:id/ |
Owner | Update listing |
| DELETE | /api/v1/rooms/:id/ |
Owner | Delete listing |
| GET | /api/v1/rooms/landmarks/ |
Public | List landmarks (for near_landmark) |
| GET | /api/v1/rooms/summary/ |
Public | COUNT/AVG for the current viewport (map badge) |
| GET | /api/v1/rooms/map-intel/stats/ |
Public | Per-area rent/demand/metro stats (intelligent map) |
| GET | /api/v1/rooms/map-intel/commute/ |
Public | Walking/driving/MRT-corridor ETA between two points |
| GET | /api/v1/rooms/eta/ |
Public | OSRM road-network ETA (car/cng/bus) with heuristic fallback |
| GET | /api/v1/rooms/map-intel/value/ |
Public | Transparent 0–100 value scores for room ids |
| GET | /api/v1/rooms/map-intel/affordability/ |
Public | % of listed rooms per area within a budget |
| GET | /api/v1/rooms/map-intel/ideal-areas/ |
Public | Ranked areas for budget + destination, with reasons |
| GET | /api/v1/rooms/map-intel/search/ |
Public | Natural-language map search (Bangla/Banglish) → intent + rooms + fly-to target |
| GET | /api/v1/rooms/geocode/?q= |
Public | Geocode a street/area (gazetteer + Nominatim) |
| GET | /api/v1/rooms/insights/ |
Auth (own listings) | Per-listing engagement + price vs area stats |
| POST | /api/v1/rooms/bulk/ |
Auth | Bulk-create listings (JSON array body) |
| GET | /api/v1/rooms/tier-catalog/ |
Public | Tier pricing + benefits (drives Promote UI) |
| GET | /api/v1/rooms/:id/similar-images/ |
Public | Rooms whose primary photo looks like this one (pHash) |
| GET | /api/v1/rooms/:id/price-recommendation/ |
Owner/Admin | Per-listing raise/hold/lower price suggestion (demand + market + interest) |
| POST | /api/v1/rooms/generate-description/ |
Auth | Deterministic AI draft — title + description + amenity tags for a listing |
| POST | /api/v1/rooms/:id/vision/analyze/ |
Owner/Admin | Run + store photo intelligence (caption, palette, observations, suggested tags) |
| GET | /api/v1/rooms/:id/vision/ |
Owner/Admin | The stored vision analysis (404 before first run) |
| POST | /api/v1/rooms/:id/vision/description/ |
Owner/Admin | AI draft title + description + tags from the listing's photos |
| POST | /api/v1/rooms/vision/search/ |
Public (30/min) | Upload a photo → look-alike listings with match_score + reasons |
Text filters: ?area=Dhanmondi&room_type=studio&price__gte=5000&price__lte=15000&is_available=true&q=cozy&ordering=-price&owner=3
Smart search: ?q=১০ হাজার এর মধ্যে uttara student room&smart=1 — natural-language parsing (budget/area/type/gender become filters), hybrid ranking over the filtered pool (neural embeddings + TF-IDF/LSA, with typo-tolerant area aliases and per-user personalization for signed-in tenants), and an nl_parsed block describing what was understood. List cards also carry an optional price_anomaly object ({predicted_price, difference_percentage, direction, badge}) when the listing's price is confidentially ≥20% above/below the predicted market price.
Geo filters:
bbox=min_lng,min_lat,max_lng,max_lat— map viewport (leafletgetBounds())near_lat=23.75&near_lng=90.39&radius_km=2— radius around a point (nearest-first)near_landmark=mirpur-10-metro&radius_km=3— radius around a named landmark/metro station
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/bookings/ |
Auth | My bookings (tenant + landlord) |
| POST | /api/v1/bookings/ |
Auth | Create booking request |
| PATCH | /api/v1/bookings/:id/ |
Auth | Update status (role-gated) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/reviews/?room=:id |
Public | Reviews for a room |
| POST | /api/v1/reviews/ |
Auth | Create review (requires approved booking) |
| GET | /api/v1/reviews/summary/?room=:id |
Public | Rating breakdown (5★ histogram + avg + verified badges) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/wishlist/ |
Auth | My wishlisted rooms |
| POST | /api/v1/wishlist/toggle/ |
Auth | Toggle wishlist (room_id body) |
| GET | /api/v1/wishlist/share-info/ |
Auth | Get my public share token + link |
| GET | /api/v1/wishlist/share/:token/ |
Public | Public read-only wishlist (no personal info, 404 on bad token) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/notifications/ |
Auth | My notifications |
| PATCH | /api/v1/notifications/:id/ |
Auth | Mark as read |
| POST | /api/v1/notifications/mark-all-read/ |
Auth | Mark all read |
| GET | /api/v1/notifications/unread-count/ |
Auth | Unread count |
| POST | /api/v1/notifications/push/subscribe/ |
Auth | Register a browser push subscription (VAPID) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/saved-searches/ |
Auth | My saved searches |
| POST | /api/v1/saved-searches/ |
Auth | Save the current filter set |
| DELETE | /api/v1/saved-searches/:id/ |
Auth | Delete a saved search |
| POST | /api/v1/saved-searches/:id/check/ |
Auth | Manual "check now" for new matches |
A daily Celery beat task (
check_saved_searches) notifies you when a new matching listing appears. A second daily beat task (send_saved_search_digests) emails you one branded summary when your saved searches matched new listings (opt out withdigest_emails_enabled).
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/users/referral/ |
Auth | My referral code, invite link + who joined |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/dashboard/stats/ |
Auth | User stats (tenant + landlord) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET/POST | /api/v1/chat/rooms/ |
Auth | List / create chat rooms |
| GET | /api/v1/chat/rooms/:id/messages/ |
Auth | Messages in a room (?search= filters content; deleted messages excluded) |
| POST | /api/v1/chat/rooms/:id/messages/ |
Auth | Send a message |
| PATCH | /api/v1/chat/rooms/:id/messages/:mid/ |
Auth | Edit your own text message (audited) |
| DELETE | /api/v1/chat/rooms/:id/messages/:mid/ |
Auth | Soft-delete your own message (audited) |
| GET | /api/v1/chat/online-status/ |
Auth | Online status of users |
| POST | /api/v1/chat/upload/ |
Auth | Upload a chat attachment |
| WS | /ws/chat/:room_id/ |
Auth | Real-time chat socket (typing, read receipts) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/payments/initiate/ |
Auth | Initiate a payment (SSLCommerz) |
| POST | /api/v1/payments/bkash/initiate/ |
Auth | Initiate a bKash payment |
| POST | /api/v1/payments/bkash/callback/ |
Public | bKash gateway callback |
| POST | /api/v1/payments/sslcommerz/success|fail|cancel/ |
Public | SSLCommerz callbacks |
| GET | /api/v1/payments/ |
Auth | My payment history |
| GET | /api/v1/payments/:id/ |
Auth | Payment detail / receipt |
| POST | /api/v1/payments/:id/refund/ |
Auth | Request a refund |
| GET | /api/v1/payments/summary/ |
Auth | Payment summary |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/recommendations/?limit=N |
Auth | Hybrid room recommendations |
| GET | /api/v1/recommendations/similar/:id/ |
Public | Content-based similar rooms (modal carousel, match % + reasons) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/pricing/predict/ |
Auth | Predict fair price for a new listing |
| GET | /api/v1/pricing/insight/:room_id/ |
Public | Price insight vs market for a room |
| GET | /api/v1/pricing/suggestion/:room_id/ |
Owner/Admin | AI pricing suggestion v2 — range, demand, time-to-rent, confidence |
| GET | /api/v1/pricing/market-stats/?area=X&room_type=Y |
Public | Raw market stats |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/v1/copilot/chat/ |
Public | Conversational discovery — search mode (intent + listings) or listing_id-grounded RAG Q&A over one listing |
| GET | /api/v1/copilot/listing/:id/ |
Public | Grounded public fact card for one listing (the RAG source document) |
| GET | /api/v1/copilot/share-summary/<id>/ |
Public | Deterministic share-ready listing summary (WhatsApp share text) |
| POST | /api/v1/copilot/advisor/ |
Public | AI Rental Advisor — budget + income → grounded budget plan (rent cap, areas, monthly breakdown) |
| POST | /api/v1/copilot/negotiate/ |
Public | AI Negotiation Assistant — comparable-price counter-offer + draft EN/BN message |
| POST | /api/v1/copilot/agreement-check/ |
Public | AI Rental Agreement Checker — one-sided clauses, advance-payment risk, missing BN-standard fields |
| POST | /api/v1/copilot/landlord/ |
Auth (owner/admin) | Landlord Copilot — price position, quality score, occupancy risk for one owned listing |
| GET | /api/v1/rooms/compare/?ids=1,2 |
Public | AI Property Comparison — 2–5 rooms side-by-side with per-area value |
| GET | /api/v1/analytics/forecast/ |
Public | Demand forecasting for area + room type (powers alerts & insights) |
| GET | /api/v1/notifications/smart/ |
Auth | Smart AI Alerts — inbox re-ranked by transparent priority (0–100) + reason |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET/PUT | /api/v1/roommates/profile/ |
Auth | Get / upsert my roommate profile |
| GET | /api/v1/roommates/matches/ |
Auth | Best-first scored match suggestions |
| GET/POST | /api/v1/roommates/requests/ |
Auth | My requests (incoming + outgoing) / send one |
| POST | /api/v1/roommates/requests/:id/action/ |
Receiver | Approve or reject a request |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/fraud/rooms/:room_id/status/ |
Public | Public badge data (drives "under review" badge) |
| GET | /api/v1/fraud/reports/ |
Auth | Reports (owner: own rooms; admin: all) — filter by status/severity |
| POST | /api/v1/fraud/rooms/:room_id/scan/ |
Owner/Admin | Re-run the detector on a room |
| POST | /api/v1/fraud/reports/:report_id/review/ |
Admin | Mark reviewed / dismissed |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/rooms/tier-catalog/ |
Public | Tier pricing + benefits catalog (drives the Promote UI) |
| POST | /api/v1/payments/tier-upgrade/initiate/ |
Owner | Start a promotion payment (Featured/Premium; amount server-side) |
Tiers: Free (default) → Featured (৳199/30d: boosted above free, badge, Home "Featured Rooms") → Premium (৳499/30d: top of search, gold badge, priority in AI recommendations). Expired promotions revert to Free automatically (expire_listings management command + query-time effective_tier).
Subscriptions — /api/v1/subscriptions/
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /subscriptions/plans/ |
Public | Active plan catalog (pricing server-side) |
| GET | /subscriptions/subscription/me/ |
Auth | My subscription + entitled features |
| POST | /subscriptions/subscription/me/ |
Auth | Start plan checkout (SSLCommerz/bKash) — returns the gateway URL |
| POST | /subscriptions/subscription/:id/cancel/ |
Auth | Cancel at period end |
| POST | /subscriptions/subscription/:id/renew/ |
Auth | Start a renewal checkout |
Revenue & payouts — /api/v1/monetization/
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /monetization/revenue/dashboard/ |
Admin | Revenue by scope, gross/platform, MRR, pending obligations, recent ledger/commissions/payouts |
| GET | /monetization/payouts/requests/ |
Admin | Payout request queue (?status=) |
| POST | /monetization/payouts/:id/decision/ |
Admin | Approve / reject a payout (balance-safe) |
| POST | /monetization/payouts/:id/mark-paid/ |
Admin | Mark an approved payout as paid (offline settlement) |
Broker network — /api/v1/brokers/
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /brokers/register/ |
Auth | Submit broker profile + first verification |
| GET/PUT | /brokers/profile/ |
Broker | Broker profile |
| GET | /brokers/dashboard/ |
Broker | Balance, pending/paid summary, recent commissions |
| GET | /brokers/commissions/ |
Broker | Own commissions (?status=) |
| GET | /brokers/payouts/ |
Broker | Own payout requests |
| POST | /brokers/payouts/request/ |
Broker | Request a payout of earned commissions |
| POST | /brokers/:id/review/ |
Admin | Review a broker verification |
Corporate housing — /api/v1/corporate/
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET/POST | /corporate/accounts/ |
Auth | List / create corporate accounts |
| GET | /corporate/accounts/:id/ |
Member/Admin | Account detail |
| GET/POST | /corporate/accounts/:id/members/ |
Owner/Admin | List / invite members by email |
| POST | /corporate/bulk-booking/ |
Owner/Admin | Book a room for several members (partial success) |
| GET | /corporate/invoices/ |
Auth | Own corporate invoices |
| GET | /corporate/admin/ |
Company admin | Overview + account approvals |
Add-on services marketplace — /api/v1/marketplace/
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /marketplace/providers/register/ |
Auth | Register a service-provider business |
| GET | /marketplace/providers/me/ |
Provider | My provider profile |
| GET | /marketplace/services/ |
Auth | Active service catalog (?category=) |
| GET | /marketplace/services/:id/ |
Auth | Service detail |
| GET/POST | /marketplace/orders/ |
Auth | My orders / place an order |
| POST | /marketplace/orders/:id/action/ |
Provider | Confirm / cancel / complete an order |
| GET | /marketplace/recommend/?booking_id= |
Auth | AI cross-sell recommendations after booking |
Insurance & credit partnerships — /api/v1/partner-services/
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /partner-services/insurance/products/ |
Public | Insurance product catalog |
| GET/POST | /partner-services/insurance/quotes/ |
Auth | My quotes / request a quote |
| POST | /partner-services/insurance/quotes/:id/action/ |
Partner | Issue / decline / cancel a quote |
| GET | /partner-services/credit/eligibility/ |
Auth | Renter credit eligibility (pre-approved limit) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/users/kyc/documents/ |
Auth | My KYC documents (admin: all) |
| POST | /api/v1/users/kyc/documents/ |
Auth | Upload a NID/passport document (multipart, 5 MB cap) |
| GET | /api/v1/users/kyc/documents/:id/file/ |
Owner/Admin | Auth-gated document file — strangers get 404 (no existence leak) |
| GET | /api/v1/users/kyc/pending/ |
Admin | Pending applications queue |
| POST | /api/v1/users/kyc/:user_id/review/ |
Admin | Approve/reject (badge sync + audit log + notification, atomic) |
| GET | /api/v1/users/kyc/audit/ |
Admin | Full KYC decision trail (who/when/note from the audit log) |
| GET | /api/v1/users/kyc/sla/ |
Admin | Review-queue health: pending count, avg review hours, 7-day trend, breach flags (oldest_pending / trend_negative) and 30-day daily trend (trend_30d) |
| GET | /api/v1/rooms/?verified=true |
Public | Only rooms owned by KYC-approved landlords |
| GET | /api/v1/users/tenant-kyc/ |
Tenant | My tenant verification status |
| POST | /api/v1/users/tenant-kyc/ |
Tenant | Submit tenant identity document (multipart) |
| GET | /api/v1/users/tenant-kyc/pending/ |
Admin | Pending tenant-verification queue |
| POST | /api/v1/users/tenant-kyc/:user_id/review/ |
Admin | Approve / reject / request resubmission (audited + notified) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/chat/safety/events/ |
Admin | Chat-safety assessments feed (metadata only, no raw content) |
| POST | /api/v1/chat/reports/ |
Auth | Report a user or message (7 categories) |
| GET | /api/v1/chat/reports/admin/ |
Admin | Moderation tickets queue (?status=) |
| POST | /api/v1/chat/reports/:report_id/action/ |
Admin | Dismiss / warn / restrict / suspend / escalate (audited) |
| POST | /api/v1/chat/block/ |
Auth | Block a user (closes the conversation both ways) |
| GET | /api/v1/chat/blocked/ |
Auth | My blocked users |
| DELETE | /api/v1/chat/block/:user_id/ |
Auth | Unblock |
| GET | /api/v1/moderation/overview/ |
Admin | Moderation queue counts (reviews + photos) |
| GET | /api/v1/moderation/reviews/ |
Admin | Review-moderation queue (?status=) |
| POST | /api/v1/moderation/reviews/:id/action/ |
Admin | Approve / reject a review (audited + notified) |
| GET | /api/v1/moderation/photos/ |
Admin | Photo-moderation queue (?status=) |
| POST | /api/v1/moderation/photos/:id/action/ |
Admin | Approve / reject a photo (audited + notified) |
| GET/POST | /api/v1/disputes/ |
Auth | My disputes / open one on an approved booking |
| GET | /api/v1/disputes/:id/ |
Participant | Dispute detail (participants only — IDOR-guarded) |
| POST | /api/v1/disputes/:id/evidence/ |
Participant | Add evidence (text / photo / document) |
| GET | /api/v1/disputes/admin/ |
Admin | All disputes (?status=) |
| POST | /api/v1/disputes/admin/:id/action/ |
Admin | Transition / resolve / reject + deposit decision (release/refund) |
| GET | /api/v1/audit/ |
Admin | Read-only audit trail (?prefix= filters by domain) |
| POST | /api/v1/analytics/events/ |
Any | First-party event capture (auth-optional, bounded, throttled) |
| GET | /api/v1/analytics/summary/ |
Admin | Analytics snapshot: totals, top events/pages, conversion funnel |
| Endpoint | Description |
|---|---|
/api/v1/docs/ |
Swagger UI |
/api/v1/redoc/ |
ReDoc |
/api/v1/schema/ |
OpenAPI schema (YAML) |
📖 Deeper reading:
docs/architecture.md(system design, data model, flows, deployment) ·docs/api-reference.md(full endpoint reference + curl examples) ·docs/ops/backup-restore.md(backup/restore runbook) ·docs/RENTORA_COPILOT.md(Copilot architecture, API, config) ·docs/AI_PRICING_V2.md(pricing suggestion v2) ·docs/DUPLICATE_IMAGE_FRAUD.md(duplicate-image detector) ·docs/INTELLIGENT_MAP.md+docs/MAP_API.md+docs/MAP_SCORING.md(intelligent map v2) ·docs/VOICE_SEARCH_PLAYBOOK.md(voice search) ·docs/LIVE_VERIFICATION.md(verified feature matrix) ·docs/PWA.md(PWA architecture, manifest, SW strategy, install/update/offline behavior) ·docs/phase-12-trust-safety-v2.md(Phase 12 Trust & Safety V2) ·docs/TENANT_KYC.md+docs/CHAT_SAFETY.md(tenant KYC + chat safety) ·docs/tier2-upgrades.md(AI chat-safety classifier, self-hosted analytics, photo forensics, OSRM ETA, ClamAV, KYC auto pre-screen, react-router v7) ·docs/tier3-upgrades.md(RAG Copilot listing mode, EN⇄BN i18n, production-grade embeddings, E2E expansion, tenant trust signals) ·docs/tier4-upgrades.md(AI advisor, negotiation assistant, agreement checker, landlord copilot, property comparison, demand forecast, smart alerts, hosted embeddings, KYC auto pre-screen, Playwright E2E) ·docs/tier5-upgrades.md(funnel analytics wiring, photo forensics v2, price recommendation, Copilot image understanding, AI listing draft) ·docs/phase-15-monetization-2.0.md(Phase 15 Monetization 2.0 — subscriptions, revenue ledger, brokers, corporate, marketplace, insurance/credit) ·docs/phase-15-communication-trust-ai.md(Phase 15 Communication & Trust AI — chat translation, support copilot, KYC OCR, review summary, market report, fraud rings) ·docs/phase-16-hardening.md(Phase 16 Hardening & Scale — embeddings, feature flags, image pipeline, Redis, rate limiting, Celery) ·docs/phase-17-final-report.md(Phase 17 Graph & Deep Trust — scam-network graph, KYC liveness, photo-geo, fake-review detection, model drift, PII masking)
- JWT authentication with access/refresh token rotation
- Unique email enforced at the API and database layers (registration, admin, seed scripts all covered)
- Rate limiting (auth: 10/hr per IP, anon: 100/hr, user: 1000/hr, payment initiation: 5/hr)
- Input sanitization via bleach on all user-generated text
- CORS configured (dev: all origins, prod: pinned domains)
- Custom error handler with consistent JSON envelope
- Production security headers (HSTS, XSS filter, content-type nosniff)
- Append-only audit log for sensitive actions (fraud-report reviews, 2FA changes) — immutable in the admin, so an audit trail cannot be rewritten
- Error tracking via Sentry (backend + frontend) and structured JSON logs (
JSON_LOGS=True) so incidents are visible and searchable - Defensive fraud scanning — a detector or queue failure can never break room creation; detector errors are isolated and logged
- Fraud engine auto-scans every new listing — flagged listings go into an admin review queue
- Password hygiene on register — zxcvbn-ts entropy scoring rejects trivially guessable passwords with actionable warnings; HaveIBeenPwned k-anonymity check warns when the chosen password appears in known data breaches (nothing but a 5-char hash prefix ever leaves the device)
- Two-factor authentication (email OTP) — challenge codes are stored hashed, TTL-bounded (10 min), attempt-limited (5 → lock) and cooldown-guarded; the login endpoint never returns tokens for a 2FA account until the code is verified
- 2FA enable is email-verified — password + emailed code are both required before
otp_enabledflips, and recovery codes (10, hashed, single-use) are minted at that moment; disabling deletes them - Passkeys — public-key only storage, sign-counter replay protection, conditional UI on login
- KYC document privacy — identity documents are served through an auth-gated endpoint (owner/admin only); the public media URL can never expose a document, and non-owners get a 404 so even file existence is hidden
- Automated security CI (
.github/workflows/security.yml) —pip-auditdependency advisories (hard-fail), Bandit MEDIUM+ static analysis (hard-fail), Djangocheck --deploy, security regression tests (upload validation / admin-only fraud / IDOR / KYC ownership),npm audit --audit-level=high(hard-fail) and a gitleaks secret scan — running on every push/PR with least-privilege permissions
Passwordless sign-in is live — the phishing-resistant successor to passwords + OTP:
| Aspect | TOTP/OTP (email) | Passkeys (WebAuthn) |
|---|---|---|
| UX friction | Open email, copy 6-digit code | One tap / biometric (Touch ID, Windows Hello) |
| Phishing resistance | Vulnerable (codes can be typed into fake sites) | Immune — bound to the exact origin (rpId) |
| Secrets | Shared secret stored server-side | Server stores public keys only |
Implemented with py_webauthn (webauthn 3.x, Duo Labs) server-side + @simplewebauthn/browser client-side. Four DRF endpoints: passkey/register/begin → passkey/register/complete (JWT-authed), passkey/login/begin → passkey/login/complete (issues JWTs). Conditional UI (mediation: 'conditional') surfaces passkeys in the browser's native autofill; a manual "Sign in with a passkey" button is the fallback. Register/revoke from Dashboard → Security → Passkeys.
Gotchas handled: WebAuthn requires a secure origin (localhost is fine; IP addresses are not); frontend/backend should share a registrable domain in production (e.g. app.example.com + api.example.com with rpId: example.com); an AbortController cancels a pending conditional ceremony when the user submits the password form.
Install Rentora as a native-feeling app — desktop (Chrome/Edge) and mobile (Android; iOS via Add to Home Screen) — without a separate codebase:
- Installable —
manifest.webmanifest(standalone display, brand#ea580ctheme), 192/512 standard + maskable icons, Apple-touch + favicon set; validated in CI against the built app - Polite install prompt — no surprise popups: a subtle "Install app" button in the navbar shows the browser's native prompt; disappears after install, cools off for a week after dismissal
- App-like window — standalone mode keeps routing, auth, the map (with shareable URL sync), voice search, Copilot, saved searches and both dashboards working exactly as in the browser; deep links open the right page
- Safe offline + offline search — a graceful "You're offline" banner, never fake data; the app shell is cached while API/auth/admin/fraud/payment data is never cached. When offline, the Rooms page searches within the cached public listings (client-side filters, "showing N cached" pill) and queued actions (wishlist) replay on reconnect via background sync
- Fresh updates — a "A new version of Rentora is available [Refresh] [Later]" banner when a new build deploys
- Native polish — Apple splash screens, dark maskable icon, iOS "Add to Home Screen" hint, and the brand flag rendered as an inline SVG (no emoji-rendering issues)
- Shortcuts — right-click / long-press the installed icon → Search Rooms · Explore Map · Post Listing
See docs/PWA.md for the manifest, icon system, service-worker strategy, update/offline behavior, security review and browser support.
Seed the database first (see Getting Started), then sign in with any of these accounts. Password for all:
demo12345
| Role | Username | What to explore |
|---|---|---|
| 🏠 Landlord | rahim.hossain |
Roommate matches (Sabbir 87%, Nadia 76%), room listing, Paid Tiers (Dashboard → Listings → Promote) |
| 🏠 Landlord | nadia.islam |
Shared Premium Gulshan listing |
| 🏠 Landlord | sabbir.rahman |
Student Room Azimpur listing |
| 🏠 Landlord | farhana.akter |
Modern Studio Mirpur listing |
| 🏠 Landlord | tanvir.islam |
Fraud dashboard (Executive Single Banani + re-scan) |
| 🏠 Landlord | demo.promoter |
Fresh FREE listing — try the Promote flow end-to-end |
| 🏠 Landlord | kyc.demo |
Unverified landlord — Dashboard → KYC: upload a document, then watch an admin approve it and the verified badge appear on your listing + chat |
| 🏠 Landlord | kyc.rejected |
Rejected KYC demo — Dashboard → KYC shows the "Why it was rejected" banner with the reviewer's note and a ready re-upload form |
Tips
- All seeded accounts are landlords — to explore the tenant side (browse, search, wishlist, book, chat), just register a fresh account from the login page (unique email required) or use the platform anonymously for browsing.
- Admin: run
python manage.py createsuperuserthen openhttp://localhost:8000/admin/— the fraud review queue, KYC review, and the append-only audit trail live there. - Sign in with the username (e.g.
rahim.hossain) or the email address (e.g.rahim.hossain@rentora.com) — both work. rahim.hossainhas a roommate profile — log in and open Roommates to see live match scores.tanvir.islamhas listings — open Dashboard → Fraud to see the risk cards and try Re-scan.kyc.rejectedstarts with a rejected document — open Dashboard → KYC to see the rejection note, then upload a clear copy to restart the review loop.- Try 2FA: Dashboard → Two-Factor Authentication → Enable 2FA (current password → emailed code → save your recovery codes). Next sign-in asks for the emailed code (or a recovery code). In development the code prints to the backend console; in production it goes to the account's email.
- Try passkeys: Dashboard → Security → Passkeys → Register a passkey (your device's biometric/PIN), then sign out and use the login page's passkey autofill or the "Sign in with a passkey" button.
💡 Screenshots can be regenerated with
docs/tools/capture-screenshots.mjs— it drives headless Chrome, mints demo tokens via Django, and saves fresh PNGs intodocs/screenshots/.
Every shipped phase with its captured screenshots (all in docs/screenshots/):
Below, the detailed phase-by-phase screenshots.
Interactive Map (MapLibre GL) — street-search autocomplete, price marker pins, clustering, split-view list, radius search, walking travel-time overlay & MRT Line 6 corridor:
Interactive Map — dark theme (auto fallback to dimmed OSM tiles keeps the map readable):
Intelligent Map — AI Smart Search (Phase 7 v2) — ask the map in Bangla/Banglish ("উত্তরায় ১২ হাজারের মধ্যে furnished room"): the parsed intent chips (area · budget · amenities), live matching rooms and the map flying to the result:
Intelligent Map — Area Intelligence — tap an area for avg/median rent, availability, 30-day demand, metro access and price trend (real data only; select up to 3 to compare):
Intelligent Map — Affordability — drag your budget and see the real % of currently listed rooms per area that fit (green/amber/red bars):
Roommate Matching — find compatible flatmates by budget, area, lifestyle & gender preference:
Fraud Detection — auto-scanned listings with risk scores & one-click re-scan from the landlord dashboard:
Login / Register — animated Dribbble-style auth dialog (live password strength meter in register mode):
Two-step verification (email OTP) — password-first login pauses at a verification-code step; tokens are issued only after the code checks out:
KYC Verification — upload identity documents from the landlord dashboard, review pending applications as admin, and see the decision trail (audit log):
KYC Review SLA Stats — the admin panel's queue-health strip (pending volume, average review time, 7-day decision trend) with red breach badges when the queue slips past 48h or trails last week:
KYC 30-day decision trend — the History view's SVG chart: bars are decisions per day, the line is average review time, so the review team can see capacity at a glance:
Phase 10 — Dashboard growth cards — the referral invite card (copy link + WhatsApp/Facebook) and the browser push-notification toggle on the Dashboard overview:
Phase 10 — Landlord Insights — per-listing views (7d/30d), wishlist saves, bookings and price vs area-average positioning:
Phase 10 — Saved Searches — save the current search from the Rooms page and get alerted about new matching listings:
Phase 11 — AI Smart Search — the ✨ AI Search toggle turns the search box into a natural-language query box: "দশ হাজার এর মধ্যে উত্তরা" (Bangla number words + Bangla area names) is understood as budget ≤ ৳10,000 in Uttara (see the "AI understood" chips under the bar) and ranked semantically — no keyword matching needed:
Phase 11++ — Rentora Copilot — the floating conversational assistant: ask in Bangla, English or Banglish ("Uttara-তে ১০ হাজারের মধ্যে room") and it searches live listings — intent chips show what it understood, every listed room is a real retrieved row (no hallucination), and follow-ups keep context:
Phase 11++ — AI pricing suggestion v2 — landlord Insights row expanded: recommended price + range, demand score, confidence, time-to-rent and the explicit Use price action (nothing changes automatically):
Phase 7 v2 — Intelligent Map — AI map search ("উত্তরায় ১২ হাজারের মধ্যে furnished room" → intent chips + real rooms + map flies to Uttara), metro commute scores, value-score pins, area intelligence with comparison, and the affordability budget view (screenshots in 🖼️ Screenshots; architecture in docs/INTELLIGENT_MAP.md):
Phase 7 v3 — Map UX polish — zoom-aware area labels + boundary highlights in light mode (left) and dark mode (right):
Phase 11++ — Cross-listing duplicate-image fraud — admin Fraud Operations filtered to the duplicate-image detector, showing the HIGH-severity match with matched-listing chips:
Verified badge — dark theme (the ✓ Verified pill stays legible in dark mode):
KYC on mobile — the identity card + verified state on a phone-sized screen:
Phase 12 — Trust & Safety V2 — two-sided marketplace integrity:
Tenant KYC — the tenant-facing identity-verification card (Start Verification state) and the Reviewing state once a document is submitted:
Verified tenant badge — the ✓ Identity Verified mark next to an identity-verified tenant's name in the chat header (landlords never see the NID or document):
Report / block — the conversation header ⋮ menu with Report user and Block user:
Chat safety feed — the admin feed of chat-safety assessments (MEDIUM / HIGH / CRITICAL, metadata only):
Review moderation queue — a held review (spam-ish contact info) with risk signals and approve/reject actions:
Photo moderation queue — a flagged duplicate-image listing photo with its matched-listing evidence:
Dispute resolution (admin) — the dispute list with evidence and the deposit decision (release / refund / partial):
Deposit protection (participant) — a tenant's dispute on the approved booking that carries the paid security deposit:
Admin Trust & Safety Operations Center — overview cards aggregating every queue (KYC, chat safety, reports, moderation, disputes):
Audit trail — the read-only trail of every Phase 12 decision (who / when / what / why):
Phase 13 — Area SEO landing page — /rooms/dhanmondi renders a crawlable per-area page with its own SEO title ("Rooms for rent in Dhanmondi, Dhaka"), meta description, area intro and the live room grid:
Phase 13 — Share on WhatsApp — the room modal's share button opens a pre-filled WhatsApp message with the deterministic AI listing summary + deep link:
Phase 13 — SMS phone sign-in — the phone-first login box in the auth dialog (masked number, resend cooldown; the backend SMS endpoints are gateway-gated and answer 503 until enabled):
Phase 14 — Photo intelligence — the landlord dashboard's per-listing panel: analyzed caption, dominant-colour palette, evidence observations, suggested amenity tags (review-then-apply) and the AI draft title + description generated from the actual photos:
Phase 14 — AI image search — upload any room photo (preview included) and Rentora finds listings that look like it:
Phase 14 — Image search results — look-alike listings ranked by perceptual similarity, each card carrying its match score badge with the reasons in the tooltip:
Home & Listing Pages:
- Branching: feature work happens on
feature/<name>branches offmain; never commit directly tomain. - Pull requests: every branch ships as a PR against
main; CI must be green (tests, coverage, lint, build) before merge. - Pre-commit: husky + lint-staged format and lint staged files on every commit.
- Environments: local dev (SQLite + runserver) → CI (GitHub Actions) → production (PostgreSQL + Daphne, Phase 8).
Sadman Chowdhury Fahim
- GitHub: @SadManFahIm
This project is licensed under the MIT License.








































