Platform blueprint · v0 · spec / pre-build

Fahiq — one system for every room, tenant and rupee

A property owner running several buildings and PGs lists rooms with photos, rent and amenities on a public site; prospects enquire and get onboarded digitally; the platform then generates every monthly bill and chases it over WhatsApp with a UPI payment link that reconciles itself.

ScaleSingle owner · multi-property
BackendDjango · DRF · Celery · Postgres
FrontendReact (Vite) + Next.js site
WhatsAppBSP adapter (AiSensy / Gupshup / Twilio / Interakt)
PaymentsRazorpay · UPI · Autopay · Payouts
RegionIndia · INR · Asia/Kolkata
01

Overview

Today the business runs on WhatsApp chats, a notebook and manual UPI follow-ups. There is no single view of vacancies across properties, utility splits are disputed, tenant records and agreements live nowhere, and collections slip because chasing is manual. Fahiq replaces that with one operating system for the entire tenant lifecycle: list → market → enquire → onboard → bill → collect → maintain → renew → move-out — with routine communication fully automated over WhatsApp.

Goals

  • Zero-effort billing cycle — invoices auto-generate on the due day; reminders and payment links go out on a schedule; payments auto-reconcile.
  • One source of truth for properties, rooms, tenants, agreements, documents and money.
  • Public storefront so vacancies fill without depending only on brokers.
  • Paperless onboarding — application, KYC, agreement e-sign, inventory, opening meter readings.
  • Owner clarity — occupancy %, expected vs collected rent, overdue aging, per-property P&L.

Out of scope for v1

  • Multi-owner SaaS with self-serve signup and per-owner billing — deferred; the data model is namespaced by organization to allow it later.
  • Full accounting-suite replacement — Fahiq integrates with / exports to Tally & Zoho instead.
  • Short-stay / nightly booking engine — later phase.

Who uses it

Owner / Admin

Runs the business

Occupancy, cash position, per-property P&L, approvals — sees everything.

Property manager

Day-to-day ops

Leads, onboarding, move-outs, tickets, meter readings for assigned properties.

Accountant

Money in / out

Invoicing, reconciliation, expenses, refunds, payouts, reports.

Field / maintenance

On the ground

Assigned tickets, meter-reading capture, inventory photos.

Prospective tenant

Browsing the site

Find a room in budget and area, see photos & rules, enquire, book.

Tenant (onboarded)

Living in a unit

See dues, pay, download receipts & agreement, raise complaints, read notices.

Success metrics

  • Collection efficiency (collected ÷ billed) ≥ 95% by day 10 of the month.
  • Average days-to-collect after the due date — trending down.
  • Average vacancy days per unit turnover — trending down.
  • % invoices sent automatically (no manual touch) — target 100%.
  • % onboardings fully digital (agreement e-signed, KYC uploaded) — target ≥ 90%.
  • Manual hours / month on billing & reminders — target near zero.
02

Product workflow

The tenant lifecycle, end to end. Every stage below is a real screen or automated job in the platform.

STAGE 1
List
Admin adds a property & units — type, rent, deposit, amenities, photos, status.
STAGE 2
Market
Available units publish to the public website with search & filters.
STAGE 3
Enquire
Visitor submits an enquiry → lead created → instant WhatsApp acknowledgement.
STAGE 4
Visit
Manager schedules a viewing; prospect & staff get reminders.
STAGE 5
Onboard
Application, KYC, agreement e-sign, move-in inventory, opening readings.
STAGE 6
Bill
On the due day the billing run creates the invoice and sends it on WhatsApp.
STAGE 7
Collect
Reminder cadence + payment link; webhook reconciles; receipt auto-sent.
STAGE 8
Maintain
Tenant raises tickets; assigned to vendors; status pushed back on WhatsApp.
STAGE 9
Renew / exit
Expiry reminders & renewal, or notice → settlement → deposit refund → unit re-listed.

Flow A — Enquiry to conversion

  1. Enquiry. Visitor submits the form on a listing (POST /public/enquiries). A Lead is created with source = website_enquiry.
  2. Acknowledge. The enquiry_ack WhatsApp template fires immediately; a "new lead" alert reaches the assigned manager.
  3. Qualify. Manager works the pipeline: New → Contacted → Visit scheduled → Visited → Negotiating → Won / Lost, logging calls and notes.
  4. Visit. A slot is booked; visit_confirmed now and visit_reminder two hours before, to prospect and staff.
  5. Convert. One click turns the won lead into an onboarding, carrying name, phone and the unit of interest.

Flow B — Digital onboarding

  1. Application. Personal details, occupation, co-occupants, emergency contact, vehicle — captured in a resumable wizard (or self-filled by the prospect via a link).
  2. KYC. Aadhaar / PAN / DL / passport + photo uploaded; each document marked pending → verified → rejected with a note. ID numbers stored masked and encrypted.
  3. Terms. Structured lease terms: start & end date, rent, deposit, lock-in, notice period, escalation %, due day, utilities & parking included.
  4. Agreement. Generated from a template with merge fields → e-signed (Digio / Leegality / Aadhaar eSign) or a signed scan uploaded; stamp / e-stamp details recorded.
  5. Inventory & meters. Move-in inspection with condition photos; opening electricity / water / gas readings with meter photos.
  6. Activate. Unit / bed assigned, status flips to Occupied, the rent schedule starts, and the onboarding_welcome WhatsApp goes out with house rules, Wi-Fi password, manager contact and payment instructions.

Flow C — Monthly billing run automated

Celery Beat job billing.run_daily_invoicing, 06:00 IST daily. Idempotent per (tenancy, period), guarded by a Redis lock.

  1. Select. Every active tenancy whose due_day is today (optionally minus lead days).
  2. Rent line. Current post-escalation rent; prorated if the tenancy started mid-period.
  3. Recurring charges. One line each — Wi-Fi, parking, maintenance, mess — prorated where applicable.
  4. Electricity. Per unit mode: sub-meter = (current − previous) × rate + fixed from the period's reading; fixed = flat amount; shared = parent bill split equally / by headcount / by ratio. No reading → electricity is skipped, the invoice is flagged electricity_pending and staff are alerted.
  5. Water. Fixed, per head, or metered — analogous.
  6. Tax. If GST is enabled, apply the rate to taxable lines and use the tax-invoice format.
  7. Totals & number. Compute subtotal, discount, tax, total; assign the next gap-free invoice number in the financial-year series.
  8. Render & post. Branded PDF generated; a rent-account ledger entry written; status set to issued; the invoice_issued (or itemized) WhatsApp template queued with the PDF and payment link.

Flow D — Collection & dunning automated

Job collections.run_reminders, 08:00 IST daily. Stops automatically the moment an invoice balance hits zero.

OffsetTemplateToneChannel
T−3rent_reminder_preFriendly heads-upWhatsApp
T0rent_due_todayNeutralWhatsApp
T+1rent_overdue_1ReminderWhatsApp
T+3rent_overdue_2FirmWhatsApp
T+7rent_overdue_3Firm + late-fee warningWhatsApp
T+15rent_overdue_finalEscalation + manager alertWhatsApp + SMS

The engine skips a send when the tenant has opted out, when the clock is inside quiet hours (queued for morning), or when a promise-to-pay date is still in the future. Every attempt is written to a ReminderLog so a given stage is never sent twice.

Flow E — Payment & reconciliation automated

  1. Link. POST /payments/link creates a Razorpay Payment Link for the invoice balance; the URL is what the reminder templates carry.
  2. Pay. Tenant pays by UPI, card, netbanking or wallet — or an approved UPI Autopay mandate auto-debits on the due day.
  3. Webhook. payment_link.paid / payment.captured arrives; signature verified; deduped on the Razorpay event id.
  4. Allocate. A Payment + allocations are written (oldest invoice first if overpaid); invoice balance & status update; a credit ledger entry is written.
  5. Receipt. A branded receipt PDF is generated, the payment_received template is sent with it attached, and any pending reminders for that invoice are cancelled.

Flow F — Maintenance ticket

  1. Tenant raises a ticket from the portal or by texting TICKET <text> on WhatsApp — category, description, photos, priority.
  2. Workflow: Open → Assigned → In progress → On hold → Resolved → Closed, with an SLA timer per priority and a tenant-visible thread separate from internal notes.
  3. Assigned to staff or a vendor; cost recorded; if it is tenant-caused damage, a charge is auto-added to the next invoice.
  4. Status changes push a WhatsApp update; on resolution the tenant rates the fix.

Flow G — Renewal & move-out

  1. Renewal. Reminders at 60 / 30 / 7 days before agreement expiry; capture new terms; regenerate & re-sign; the rent schedule extends.
  2. Notice. Tenant (portal / WhatsApp) or owner records notice; the system computes the last day from the notice period and lock-in; notice_ack is sent.
  3. Settlement. Inventory re-check with damage deductions, final meter readings & utility bill, unpaid dues — the deposit refund is computed and a settlement statement generated.
  4. Close. On tenant acknowledgement the refund pays out (Razorpay Payout or manual); the unit returns to Available (or Under maintenance with a turnover task) and re-lists.
03

Functional requirements

Seventeen modules. Every capability is tagged with the phase it lands in.

P1 MVPP2 fast-followP3 growthP4 advanced
ModuleKey capabilitiesPhases
A · Property & room management Multiple properties with geo-location & photos; Property → Block → Floor → Unit → Bed hierarchy; unit types 1RK / Studio / 1–4BHK+ / PG bed (single–dormitory) / commercial; furnishing, area, commercials (rent, deposit, maintenance, lock-in, notice, escalation, due day); photo & video galleries, floor plans, 360° tour; property- and unit-level amenity checklist (~40 items); status available / booked / occupied / notice / maintenance / blocked + available-from; tenant-type & house rules; nearby landmarks; rent-revision history; CSV import & bulk edit; clone unit. P1 P2 P3
B · Public website Landing + search with filters (locality, budget, type, furnishing, availability, amenities, tenant type, sharing); listing cards + detail page (gallery, rent breakdown, rules, map, nearby, similar); enquiry & schedule-a-visit forms; WhatsApp click-to-chat; book-now token payment; shortlist; verified reviews; per-locality SEO pages, sitemap, JSON-LD; CMS-lite content; English / Hindi; PWA. P1 P2 P3
C · Lead / enquiry CRM Capture from website, WhatsApp, call, walk-in, broker, referral; pipeline stages with lost-reason; assignment, follow-up reminders, activity timeline; auto acknowledgement; visit scheduling with calendar; convert-to-onboarding; duplicate detection; source & funnel reporting; cold-lead drip. P1 P2 P3
D · Tenant onboarding Digital application + co-occupants; KYC upload & verification; rental-agreement generation + e-sign; police / tenant-verification form; structured lease terms; move-in inventory with photos; opening meter readings; unit / bed assignment + welcome message; guarantor & co-tenant records; self-onboarding link. P1 P2 P3
E · Tenancy / lease lifecycle Active-tenancy register with full profile; automatic monthly rent schedule; anniversary rent escalation; renewal workflow + expiry reminders; notice-to-vacate with computed last day; move-out settlement; transfer between units; tenancy history; blacklist; corporate lease. P1 P2 P3
F · Billing & invoicing Charge types (rent, deposit, electricity, water, maintenance, wifi, mess, housekeeping, parking, gas, late fee, damage, one-time, custom); per-tenancy recurring charges; electricity by sub-meter / fixed / shared split; water fixed / per-head / metered; automatic monthly batch + ad-hoc invoices; proration; auto late fees with cap; branded invoice PDF; credit notes / waivers with approval; partial payments & allocation rules; tenant ledger & statement; aging buckets; separate deposit ledger; gap-free numbering; GST tax invoice; TDS-on-rent note. P1 P2 P3
G · Payments & collections Razorpay Payment Links per invoice; webhook auto-reconciliation; receipts; offline payment entry + approval; UPI Autopay / e-mandate; configurable reminder cadence with escalation; collection dashboard; promise-to-pay; deposit refund via Payout; owner payout tracking; convenience-fee pass-through; BBPS bill pay. P1 P2 P3 P4
H · WhatsApp automation BSP adapter with swappable provider; ~35 approved templates; variable merge; daily scheduler; two-way inbound with keyword auto-replies; broadcasts to segments; delivery tracking with SMS / email fallback; opt-out, quiet hours, per-message cost log; template-management UI; AI concierge. P1 P2 P3 P4
I · Maintenance & tickets Tenant-raised tickets with photos & priority; assignment to staff / vendors; SLA timers & escalation; internal vs tenant-visible thread; vendor directory & rate cards; recharge tenant-fault costs; preventive-maintenance schedules; asset / appliance register; common-area tickets; WhatsApp status updates & ratings. P1 P2 P3
J · Staff / team Role-based staff accounts; property-scoped access; audit trail; task management & checklists; field-staff check-in; internal notes & mentions. P1 P2 P3
K · Accounting & finance Auto income capture; categorized expenses with receipts, per property; per-property P&L with yield; cash-flow statement; owner drawings; exports to Tally / Zoho; GST output report; e-invoicing; expense-bill OCR. P2 P3 P4
L · Reports & analytics Rent roll; occupancy; collections; aging; upcoming vacancies; expiring agreements; utility-consumption trends; lead funnel & source performance; vacancy days; churn / retention; maintenance cost; custom date ranges + PDF / Excel export; scheduled email reports. P1 P2 P3
M · Tenant self-service portal Phone-OTP login; dues & one-tap pay; invoices, receipts, ledger / statement; agreement & KYC status; raise / track tickets; submit meter reading; announcements feed; move-out request; profile edits; PG roommate & mess info; refer-a-friend; contact manager. P1 P2 P3
N · Notifications (multi-channel) WhatsApp, email, SMS, in-app; per-event templates; per-user channel preference & opt-out; staff alerts (new lead, payment, ticket, send failure, notice given, agreement expiring, missing meter reading, low occupancy); daily digest option. P1 P2
O · Documents & templates Central document vault per tenant / unit / property; generated invoice, receipt & ledger PDFs; merge-field templates (agreement, police verification, rent receipt, notice letter, settlement statement, NOC); template versioning; signed-URL access & expiry tracking; watermarking. P1 P2 P3
P · Configuration / settings Business profile & branding; master data (properties, amenities, charge types & rates); billing policy (grace, late fee, numbering, financial year); electricity slabs & water charges; integration credentials with test buttons; reminder-cadence editor; users / roles / property assignment; localization; public-site CMS; agreement clause library. P1 P2 P3
Q · Advanced / future React Native apps (tenant + field); smart locks & visitor management; IoT smart-meter auto-read; Aadhaar / DigiLocker KYC; channel manager (NoBroker, MagicBricks, 99acres, Housing, OLX); dynamic pricing; mess & laundry management; referral & loyalty; AI (chatbot, default-risk scoring, ticket triage, OCR); renter's insurance; BBPS; short-stay mode; multi-owner SaaS. P4
04

Non-functional requirements

Security

  • Authentication. Staff: email + password (Argon2), mandatory TOTP 2FA for Owner/Admin & Accountant, lockout after 5 failed attempts. Tenant: phone + 6-digit OTP, 5-minute TTL, rate-limited, single-use. Short-lived access JWT (15 min) + rotating refresh token with reuse detection.
  • Authorization. RBAC plus object-scoping by property, enforced at the queryset layer. Deny by default. Sensitive changes route through an approval workflow; waivers & discounts are amount-limited per user.
  • Data protection. TLS 1.2+ with HSTS; DB volume encryption; field-level encryption (Fernet / KMS) for integration credentials and KYC ID numbers; KYC files in a separate stricter bucket with 2–5 minute signed URLs. PII masked in logs and Sentry.
  • Payments. Card / UPI data never touches our servers — Razorpay Checkout & hosted links only; we hold tokens and references, keeping PCI scope at SAQ-A.
  • Webhooks. Signature verified (Razorpay, BSP), idempotent processing, raw payload stored for replay, IP allowlist where offered.
  • Hardening. CSRF on session routes, locked CORS, strict CSP on the public site, security headers, dependency & secret scanning in CI, throttling on auth / OTP / enquiry, bot protection on public forms, upload type / size allowlist with image re-encoding and AV scan.
  • Audit. Every money / status / agreement / KYC / permission change writes an immutable before→after log entry with actor, IP and time.

Compliance (India)

  • DPDP Act 2023 — explicit consent capture (WhatsApp opt-in, KYC purpose), consent records, purpose limitation, retention schedule, data-subject access / erasure handling, breach process, named grievance officer.
  • WhatsApp / Meta policy — approved templates only for business-initiated messages, correct utility vs marketing categorization, opt-out strictly honoured.
  • GST (if registered) — compliant tax-invoice format, sequential numbering, retention.
  • Retention defaults — financial records 8 years; KYC per statutory need; message bodies 18 months (metadata longer); server logs 90 days.

Performance & scalability

  • API p95 < 300 ms for list / detail endpoints at target scale (≤ 2,000 units, ≤ 5,000 active tenancies, ≤ 50 staff).
  • Public listing pages: LCP < 2.5 s on mid-tier 4G, INP < 200 ms, CLS < 0.1.
  • Pagination everywhere; no unbounded queries; select_related / prefetch_related; indexes on the hot paths.
  • Redis caching for public listing & facet queries, dashboard KPI aggregates and report results; media on a CDN with content-hash URLs and AVIF / WebP.
  • Billing run is chunked, resumable and idempotent; a bad tenancy fails alone, never the batch. Separate Celery queues (default, billing, messaging, pdf, exports).
  • Stateless API containers scale horizontally; exports & broadcasts are background jobs with progress.

Reliability & availability

  • Target 99.5% monthly app availability; billing & reminder jobs alert on a missed or late run ("last successful run" freshness monitor).
  • Daily Postgres snapshots + PITR (WAL), ≥ 14-day retention, quarterly restore drills — RPO ≤ 5 min with PITR, RTO ≤ 4 h.
  • All scheduled jobs idempotent and Redis-locked; safe to re-run.
  • Webhook processing at-least-once with dedupe, dead-letter queue, backoff and a manual replay tool.
  • Outbound sends retry then fall back WhatsApp → SMS → email; staff are alerted if a tenant is unreachable on every channel.
  • If the BSP or Razorpay is down, invoices still generate and queue, flushing when the provider recovers.
  • Zero-downtime deploys; backward-compatible migrations (expand → migrate → contract).

Data integrity

  • Invoices immutable after issue — the only permitted post-issue mutation is an audited late-fee line; other corrections are credit notes.
  • Ledgers append-only; balances derived and materialized, with a nightly reconciliation check that alerts on drift.
  • Gap-free invoice / receipt numbering via a DB sequence + unique constraint per financial year.
  • Soft-delete for anything with financial history; every money mutation inside a DB transaction; Decimal arithmetic with documented rounding.

Observability

  • Structured JSON logs with request / task / tenancy correlation ids; Sentry on API, workers and both frontends with PII scrubbing.
  • Business metrics: invoices generated, messages sent / delivered / failed, reminder queue depth, payments reconciled, reconciliation lag, webhook latency, Celery queue lengths, billing-run duration.
  • Paging alerts: billing run failed / late, webhook backlog, message failure rate, reconciliation drift, backup failed, error-rate spike.
  • External uptime monitoring on the public site, the API and job freshness.

Accessibility & UX quality

  • WCAG 2.1 AA on the public site and tenant portal — semantic HTML, labelled controls, keyboard navigation, visible focus, AA contrast, alt text, reduced-motion support.
  • Responsive: site & portal mobile-first; dashboard usable on tablet; field flows (meter reading, ticket update) usable on a phone.
  • Friendly error copy mapped from the RFC-7807 detail; empty states name the next action; destructive actions confirm with a reason.
  • Localization-ready — INR, Asia/Kolkata, dd MMM yyyy, English / Hindi.
05

Roles & permissions

Two populations: staff users in the dashboard (role-based, property-scoped) and tenant users in the portal (scoped to their own tenancy). Public visitors are anonymous.

CapabilityOwnerManagerAccountantFieldFront deskRead-only
See all propertiesassignedassigned/allassignedassignedassigned/all
Create / edit properties & units
Manage leads & visitsview
Onboard a tenant / verify KYConboard
Generate agreement & trigger e-sign
Edit tenancy termsapproval
Enter meter readings
Generate invoices
Discounts / credit notes / waivers≤ limit≤ limit
Record / approve offline payments✅ / ✅record✅ / ✅record
Issue refunds / payouts
Edit reminder cadence / templates
Send broadcastsown property
Manage maintenance ticketsassignedcreateview
Record expenses
View financial reports & P&Lown propertyassigned/all
Manage users & roles
Edit integration credentials & settings

approval = the action creates a pending change-request the Admin approves. ≤ limit = allowed up to a per-user rupee cap, above which it needs approval. Property scoping is filtered in the queryset, not just the view.

Authentication by population

PopulationMethod
StaffEmail + password; mandatory TOTP 2FA for Owner/Admin & Accountant; JWT session
TenantPhone + OTP (SMS, WhatsApp secondary); optional device PIN
Public visitorNone; optional email magic-link only to sync a shortlist
Service / webhooksSigned webhook secrets; IP allowlist where supported

Tenant portal scope

A tenant only ever sees data where tenancy.tenant == request.user.tenant (or they are a listed co-tenant): their own invoices, receipts, ledger, agreement, KYC status, tickets and property announcements. They can pay their own invoices, raise / rate their own tickets, submit their own meter readings (if enabled), initiate a move-out, and edit contact fields — KYC edits go to a review queue. They cannot see other tenants, other units, staff notes or any financial totals beyond their own.

06

System architecture

A Django + DRF API with a Celery worker and Beat scheduler; PostgreSQL as the system of record; Redis for cache, locks and the Celery broker; S3 / R2 for media and generated PDFs. Three React frontends talk to the same API.

                         ┌──────────────────────── Clients ────────────────────────┐
  Public visitor  ─────►   Public Website (Next.js · SSR/SSG for SEO)
  Tenant          ─────►   Tenant Portal  (React + Vite SPA)
  Staff / Owner   ─────►   Admin Dashboard (React + Vite SPA)
                         └────────────────────────────┬───────────────────────────┘
                                                      │  HTTPS / JSON (REST, /api/v1)
                                                      ▼
                         ┌──────────── Django + Django REST Framework ────────────┐
                         │  Auth · RBAC · domain services · serializers · OpenAPI │
                         └──┬───────────────────┬────────────────────┬───────────┘
                            │                   │                    │
                     ┌──────▼─────┐      ┌──────▼──────┐      ┌──────▼────────┐
                     │ PostgreSQL │      │   Redis     │      │ Object storage│
                     │ (records)  │      │ cache+broker│      │  S3 / R2      │
                     └────────────┘      └──────┬──────┘      └───────────────┘
                                                │
                                    ┌───────────▼────────────┐
                                    │  Celery workers        │
                                    │  Celery Beat (cron)    │
                                    │   billing · reminders  │
                                    │   escalations · PDFs   │
                                    │   webhook retries      │
                                    └───────────┬────────────┘
                                                │ outbound
   ┌──────────────┬──────────────┬──────────────┼───────────────┬───────────────┐
   ▼              ▼              ▼              ▼               ▼               ▼
 WhatsApp BSP   Razorpay      SMS gateway    Email (SES/     e-sign          Maps /
 (AiSensy/…)  (Links·Autopay· (MSG91/Twilio) SendGrid/SMTP)  (Digio/         Sentry
              Payouts·webhook)                                Leegality)

 Inbound webhooks → Django receivers → verified, deduped, queued for async processing.

Components

ComponentTechResponsibility
API serviceDjango 5 · DRF · Gunicorn/UvicornBusiness logic, auth, REST API, webhook receivers, admin
WorkerCeleryAsync & scheduled jobs — billing, reminders, PDFs, notifications, webhook processing, exports
SchedulerCelery Beat (DB schedule)Fires the daily & periodic jobs
Admin dashboardReact + Vite + TSStaff UI
Public websiteNext.js (App Router)Marketing, listings, enquiry / booking — SSR/SSG for SEO
Tenant portalReact + Vite + TSTenant self-service (shares the design system with the dashboard)
DatabasePostgreSQL 16 (managed)System of record
RedisManaged RedisCache, Celery broker + result backend, rate-limit counters, OTP store, job locks
Object storageS3 / Cloudflare R2Photos, video, generated PDFs, KYC docs — private buckets, signed URLs

Scheduled jobs (Celery Beat)

JobSchedule (IST)Purpose
billing.run_daily_invoicing06:00 dailyBuild & issue invoices for tenancies due today; render PDF; queue the invoice message. Idempotent per (tenancy, period).
collections.run_reminders08:00 dailyEvaluate the cadence for every unpaid invoice and send the due reminder with its payment link; skip if paid / opted-out / quiet hours / promised.
billing.apply_late_fees09:00 dailyAdd a late-fee line once per invoice after the grace period.
tenancies.escalate_rent02:00 dailyApply rent escalation on tenancies hitting their anniversary.
tenancies.expiry_reminders07:00 daily60 / 30 / 7-day agreement-expiry reminders + staff alert.
meters.reading_reminders10:00 dailyAlert staff about units missing a current-month reading before billing.
maintenance.preventive_due07:30 dailyCreate / notify preventive-maintenance tasks that are due.
payments.reconcile_pendingevery 30 minPoll Razorpay for links still "created" past the webhook grace; sync status.
messaging.retry_failedevery 15 minRetry failed sends with backoff; fall back channel after N tries.
reports.email_digestsMon 08:00 / 1st 08:00Weekly collections + monthly P&L email to the owner.
common.nightly_backup_check01:00 dailyVerify the last DB + media backup succeeded; alert if not.

Integrations

IntegrationPurposeDirection
WhatsApp BSPSend template messages; receive delivery status & inbound repliesout + webhook
RazorpayPayment Links, UPI Autopay mandates, Payouts, webhooksout + webhook
SMS (MSG91 / Twilio)OTP + fallback notificationsout
Email (SES / SendGrid / SMTP)Invoices, receipts, digests, staff alertsout
e-sign (Digio / Leegality)Rental-agreement signingout + webhook
Maps (Google / Mapbox)Geocoding on save; map view on the siteout
SentryError monitoring — API, workers, frontendsout

WhatsApp adapter: one WhatsAppProvider interface (send_template, parse_status_webhook, parse_inbound_webhook) with concrete AiSensyProvider / GupshupProvider / TwilioWhatsAppProvider / InteraktProvider. Switching provider is a config change plus a template-name remap — no domain code changes.

Consistency rules

  • Money is Decimal(12,2), currency stored explicitly (INR in v1); rounding documented per charge.
  • Invoices immutable once issued; ledger append-only; balances derived and cached.
  • Idempotency keys on invoice generation (tenancy:period), payments (razorpay_payment_id) and outbound messages (event_id).
  • Soft-delete for tenants, units and tenancies with financial history — never hard-deleted.
  • Store UTC, present IST.

Environments & delivery

  • local — Docker Compose: api, worker, beat, postgres, redis, minio, mailhog.
  • staging — mirrors prod; sandbox BSP / Razorpay keys; seeded demo data.
  • production — managed Postgres + Redis; object storage; HTTPS; backups; monitoring.
  • One container image for api / worker / beat (different command). Nginx for TLS. CI: ruff → mypy → pytest → build → migrate → deploy. Frontends build eslint → tsc → vitest → deploy.
07

Data model

All tables carry id (uuid), created_at, updated_at; money is Decimal(12,2) INR; business tables carry organization_id (one org in v1, namespaced for a future SaaS).

Organization 1─┬─* User(staff) ─* PropertyAssignment *─ Property
               │
               ├─* Property 1─* Block 1─* Floor 1─* Unit 1─* Bed
               │                                     ├─* MediaAsset
               │                                     ├─* UnitAmenity *─ Amenity
               │                                     └─* Meter 1─* MeterReading
               │
               ├─* Lead 1─* LeadActivity  └─1 VisitSchedule
               │
               ├─* Tenant 1─* TenantDocument(KYC)  └─* CoTenant / Guarantor
               │
               ├─* Tenancy ──1 Unit / Bed
               │       ├─1 RentalAgreement ─* AgreementVersion
               │       ├─* RecurringCharge ─ ChargeType
               │       ├─* Inspection(move-in/out) ─* InspectionItem
               │       ├─* Invoice 1─* InvoiceLineItem
               │       │        ├─* Payment ─* PaymentAllocation
               │       │        └─* CreditNote
               │       ├─* LedgerEntry          (rent account, append-only)
               │       ├─* DepositLedgerEntry   (deposit account, append-only)
               │       ├─* ReminderLog · PromiseToPay
               │       └─1 MoveOutSettlement
               │
               ├─* MaintenanceTicket ─* TicketComment / TicketAttachment ─ Vendor
               ├─* PreventiveMaintenance ─* PreventiveTask   ├─* Asset ─ Unit
               │
               ├─* Expense ─ ExpenseCategory / Vendor / Property   ├─* OwnerPayout
               │
               ├─* NotificationTemplate · MessageLog · InboundMessage
               ├─* Broadcast ─* BroadcastRecipient   ├─* Announcement ─* AnnouncementAck
               │
               ├─* Document(vault)  · AuditLog · ChangeRequest · Review
               └─1 Settings / IntegrationCredentials

Entity groups

Access

Organization, Settings, IntegrationCredentials (encrypted), User, PropertyAssignment.

Property & inventory

Property, Block, Floor, Unit, Bed, Amenity, UnitAmenity, PropertyAmenity, MediaAsset, Meter, MeterReading.

Leads

Lead, LeadActivity, VisitSchedule.

Tenants & tenancies

Tenant, TenantDocument, CoTenant, Guarantor, Tenancy, RentalAgreement, AgreementTemplate / Version, Inspection, InspectionItem.

Billing & ledger

ChargeType, RecurringCharge, Invoice, InvoiceLineItem, CreditNote, Payment, PaymentAllocation, LedgerEntry, DepositLedgerEntry, MoveOutSettlement, ReminderLog, PromiseToPay.

Maintenance

MaintenanceTicket, TicketComment, TicketAttachment, Vendor, PreventiveMaintenance, PreventiveTask, Asset.

Messaging

NotificationTemplate, MessageLog, InboundMessage, Broadcast, BroadcastRecipient, Announcement, AnnouncementAck.

Finance

ExpenseCategory, Expense, OwnerPayout.

Governance

Document, AuditLog, ChangeRequest, Review, WebhookEvent.

Key derived rules

ValueRule
Unit becomes occupiedWhen a Tenancy goes active; back to available on ended (or maintenance if a turnover task is open).
Tenancy outstandingSum of unpaid invoice balances = last LedgerEntry.running_balance on the rent account.
Electricity (sub-meter)(current − previous) × rate + fixed_charge; a reading must exist for the period or the run flags it.
Electricity (shared)Parent bill split by equal / headcount / ratio; rounding remainder assigned to the largest share so it reconciles exactly.
Prorationrent × days_occupied_in_period ÷ days_in_period, rounded per policy (default: actual days).
Late feeOnce per invoice after due_date + grace_days: flat | percent × balance | per_day × days, capped at late_fee_cap.
Rent escalationOn the start-date anniversary: rent ×= (1 + escalation_percent ÷ 100); writes escalation_last_applied_on.
Deposit refunddeposit_held − outstanding_dues − damage_deductions − other_deductions, floored at 0; negative → tenant owes.
Aging buckettoday − invoice.due_date → 0–30 / 31–60 / 61–90 / 90+.
08

WhatsApp automation

WhatsApp is the primary notification channel, delivered through a BSP (AiSensy / Gupshup / Twilio / Interakt) behind a single swappable adapter. Business-initiated messages use pre-approved templates; variable order matches what is registered on the BSP.

Template catalogue (representative)

EventTriggerAttachPhase
enquiry_ackWebsite enquiry createdP1
onboarding_welcomeTenancy activatedHouse-rules PDFP1
invoice_issuedMonthly / ad-hoc invoice issuedInvoice PDFP1
electricity_bill · water_bill · bill_genericUtility line billed separatelyP1
rent_reminder_pre · rent_due_today · rent_overdue_1Cadence T−3 / T0 / T+1P1
rent_overdue_2/3/final · late_fee_appliedCadence T+3 / T+7 / T+15; late fee addedP2
payment_receivedPayment successReceipt PDFP1
otp_loginTenant portal loginP1
agreement_ready · agreement_signed_copye-sign sent / completedSigned PDFP2
visit_confirmed · visit_reminderVisit scheduled / 2 h beforeP2
autopay_setup · autopay_failedMandate active / debit failedP2
agreement_expiry_60/30/7 · renewal_offerRenewal windowP2 P3
notice_ack · moveout_settlement · deposit_refund_initiatedNotice / settlement / refundStatement PDFP2
ticket_created/status/resolvedMaintenance ticket lifecycleP2
preventive_notice · announcement · festival_greetingPlanned work · broadcast · seasonaloptionalP2 P3
meter_reading_requestAsk tenant to submit a readingP2

Reminder cadence (editable)

[
  { "offset_days": -3, "event": "rent_reminder_pre", "channel": "whatsapp" },
  { "offset_days":  0, "event": "rent_due_today",     "channel": "whatsapp" },
  { "offset_days":  1, "event": "rent_overdue_1",     "channel": "whatsapp" },
  { "offset_days":  3, "event": "rent_overdue_2",     "channel": "whatsapp" },
  { "offset_days":  7, "event": "rent_overdue_3",     "channel": "whatsapp" },
  { "offset_days": 15, "event": "rent_overdue_final", "channel": "whatsapp", "also": ["sms"] }
]

The daily job matches today − due_date against the entries, sends once per stage (tracked in ReminderLog), and stops the moment the balance is zero. If bill_delivery_mode = consolidated, only invoice_issued is used and the per-utility templates stay dormant.

Two-way (inbound) keywords

KeywordAuto-reply
BALANCE / DUECurrent outstanding + a payment link
PAYA fresh link for the oldest unpaid invoice
RECEIPT / STATEMENTLast receipt / ledger statement PDF
TICKET <text>Creates a maintenance ticket, replies with the number
STOP / STARTSets / clears opt-out
anything elseHelp text + routed to the staff inbox

Guardrails

  • Opt-in captured at onboarding (logged); opt-out always honoured; quiet hours 21:00–08:00 IST for non-critical sends.
  • Approved templates only for business-initiated messages; correct utility vs marketing category; marketing respects opt-out strictly.
  • Payment links are per-invoice and expiring; no sensitive IDs in message bodies.
  • Delivery status tracked (sent / delivered / read / failed) with retry then SMS / email fallback; per-message cost logged.
  • A console provider for local / CI; POST /messages/test for template QA.
09

Billing & payments

Charge types

  • Rent
  • Security deposit
  • Electricity
  • Water
  • Maintenance / society
  • Wi-Fi / internet
  • Mess / food
  • Housekeeping
  • Parking
  • Gas / cylinder
  • Late fee / penalty
  • Damage / repair recovery
  • One-time (key deposit, painting)
  • Custom

Electricity billing modes

ModeAmount
Sub-meter(current − previous) × rate_per_unit + fixed_charge, from the period's reading + meter photo. Optional tiered slabs.
FixedA flat monthly amount per unit.
Shared / splitParent property bill split across sibling units — equal, by headcount, or by custom ratio; rounding remainder to the largest share.

Water billing mirrors this (fixed / per-head / metered). If no reading exists at billing time, electricity is skipped, the invoice is flagged electricity_pending, staff are alerted, and a later reading produces a supplementary line.

Invoice → ledger example

DateDescriptionDebitCreditBalance
2026-09-01Invoice INV-2026-0043 (Sep)16,462.0016,462.00
2026-09-04Payment · UPI · RCPT-009116,462.000.00
2026-10-01Invoice INV-2026-0061 (Oct)15,930.0015,930.00
2026-10-09Late fee (Oct)300.0016,230.00

Payments

  • Online — Razorpay Payment Link per invoice (UPI / card / netbanking / wallet); webhook payment_link.paid → verify signature → dedupe → Payment + allocations (oldest-first on overpayment) → ledger credit → receipt PDF → payment_received → cancel pending reminders.
  • UPI Autopay — one-time e-mandate; Razorpay auto-charges on the due day; subscription.charged books it identically; a failed debit sends autopay_failed and falls back to the normal cadence.
  • Offline — cash / cheque / bank transfer entered with proof; pending until an Accountant / Admin approves; then same downstream (allocation, ledger, receipt).
  • Partial & allocation — invoice goes partially_paid; allocation order oldest-first, then rent → utilities → other → late fee; overpayment becomes a credit applied to the next invoice.
  • Refunds & payouts — deposit refund via Razorpay Payout or manual, tracked on the deposit ledger; owner payouts recorded per property for the P&L.

Move-out settlement

refund = deposit_held
       − outstanding_rent_ledger_balance
       − Σ inspection.damage_deductions
       − other_deductions   (cleaning, unpaid utilities from final readings)
       (floored at 0; if negative, tenant owes → final invoice)
Policies to confirm with the owner: carry-forward as a line vs independent invoices (default independent) · proration basis (default actual days) · electricity on the main invoice or a separate message (bill_delivery_mode) · grace period & late-fee formula & cap · allocation priority · tenant-submitted meter readings on/off · GST registration · deposit months & non-refundable deductions · website token amount & hold duration.
10

Tech stack

Backend

ConcernChoice
Language / frameworkPython 3.12+ · Django 5.x · Django REST Framework
API schema & docsdrf-spectacular (OpenAPI 3 → Swagger UI, TS client)
Authdjangorestframework-simplejwt · django-otp / pyotp (2FA) · custom phone-OTP backend
Async / schedulingCelery 5 · django-celery-beat · Redis broker
Database / cachePostgreSQL 16 · Redis (django-redis)
Filesdjango-storages + boto3 → S3 / Cloudflare R2 (private, signed URLs)
PDFWeasyPrint (HTML → PDF) — invoices, receipts, statements, agreements
Domain helpersDecimal / django-money · django-phonenumber-field · django-filter · django-import-export · Pillow
Payments / messagingrazorpay SDK · httpx BSP adapters · MSG91 / Twilio SMS · django-anymail (SES / SendGrid)
Securitycryptography (Fernet) for credential encryption · django-ratelimit · pip-audit · gitleaks
Qualityruff · mypy + django-stubs · pytest + pytest-django + factory_boy + freezegun · coverage.py

Frontend

ConcernChoice
Dashboard & portalReact 18 + Vite + TypeScript · React Router v6
Public websiteNext.js (App Router) — SSR/SSG for SEO
Server state / HTTPTanStack Query · Axios wrapper with token refresh
API typesopenapi-typescript + orval, generated from /api/schema/
Client state / formsZustand · React Hook Form + Zod
UITailwind CSS + shadcn/ui (Radix) · TanStack Table · Recharts · date-fns (Asia/Kolkata)
Maps / uploadsMapLibre / Leaflet · react-dropzone with presigned S3 uploads
PaymentsRazorpay Checkout JS + hosted Payment Links
i18n / PWAi18next (English / Hindi) · vite-plugin-pwa (portal)
Qualityeslint · prettier · Vitest + React Testing Library · Playwright (E2E)

Why this stack

  • Django + DRF — the fastest path to a correct, auditable domain model with migrations, admin and mature auth; ideal for money and records.
  • Celery + Beat — the billing and reminder automation is inherently scheduled and async; this is the standard tool.
  • PostgreSQL — transactions, constraints, JSONB for flexible config, strong indexing.
  • React + Vite for the data-dense dashboard; Next.js only where SEO needs server rendering.
  • Razorpay — first-class UPI, Payment Links (ideal for WhatsApp), UPI Autopay and Payouts.
  • BSP adapter — no lock-in; the WhatsApp provider is a config choice.
11

Project structure

A monorepo — pnpm workspaces for the frontends beside a Django backend directory.

fahiq/
├─ backend/                    # Django project
│  ├─ config/                  # settings (base/dev/prod), urls, celery, asgi/wsgi
│  ├─ apps/
│  │  ├─ accounts/             # staff users, roles, permissions, 2FA, property assignment
│  │  ├─ organization/         # business profile, settings, encrypted integration credentials
│  │  ├─ properties/           # property, block, floor, unit, bed, amenity, media
│  │  ├─ catalog/              # public read models, search, filters, SEO pages
│  │  ├─ leads/                # enquiries, pipeline, visits, activities
│  │  ├─ tenants/              # tenant persons, KYC documents, co-tenants, guarantors
│  │  ├─ tenancies/            # lease, terms, escalation, renewal, notice, move-out, transfer
│  │  ├─ agreements/           # templates, generation, e-sign, versions
│  │  ├─ inspections/          # move-in/out inventory, condition photos
│  │  ├─ meters/               # meter definitions, readings, consumption
│  │  ├─ billing/              # charge types, recurring charges, invoices, proration, late fees, numbering
│  │  ├─ payments/             # razorpay, links, autopay, webhooks, offline, receipts, refunds, payouts
│  │  ├─ ledger/               # tenant ledger, deposit ledger, aging, statements
│  │  ├─ collections/          # reminder cadence engine, dunning, promise-to-pay
│  │  ├─ maintenance/          # tickets, SLA, vendors, preventive schedules, assets
│  │  ├─ messaging/            # templates, channel router, WhatsApp BSP adapter, delivery logs, inbound
│  │  ├─ finance/              # expenses, categories, vendors, P&L, owner payouts, exports
│  │  ├─ reports/              # rent roll, occupancy, collections, aging, funnel, exports
│  │  ├─ documents/            # document vault, PDF rendering, signed URLs
│  │  ├─ audit/                # audit log, change requests / approvals
│  │  └─ common/               # base models, money & phone helpers, pagination, permissions
│  ├─ manage.py  ·  pyproject.toml  ·  Dockerfile
│
├─ frontend/
│  ├─ packages/
│  │  ├─ api-client/           # generated TS client + shared types
│  │  ├─ ui/                   # shared design-system components
│  │  └─ config/               # eslint / tsconfig / tailwind presets
│  └─ apps/
│     ├─ dashboard/            # React + Vite (staff)
│     ├─ portal/               # React + Vite (tenant)
│     └─ website/              # Next.js (public, SEO)
│
├─ infra/
│  ├─ docker-compose.yml       # local: db, redis, minio, mailhog, api, worker, beat
│  └─ nginx/  ·  render.yaml | fly.toml | terraform/
│
├─ docs/                       # the Markdown specification (01–15) + this page
└─ .github/workflows/          # CI

Domain logic lives in services.py per app (thin views, thin models, fat services); scheduled / async entry points in tasks.py per app.

Environment variables (excerpt)

# core
DJANGO_SETTINGS_MODULE=config.settings.dev
SECRET_KEY=…            DATABASE_URL=postgres://…      REDIS_URL=redis://…
FIELD_ENCRYPTION_KEY=…  # Fernet key for IntegrationCredentials

# storage
AWS_S3_ENDPOINT_URL=…   AWS_STORAGE_BUCKET_NAME=…   KYC_BUCKET_NAME=…
AWS_ACCESS_KEY_ID=…     AWS_SECRET_ACCESS_KEY=…

# payments
RAZORPAY_KEY_ID=…  RAZORPAY_KEY_SECRET=…  RAZORPAY_WEBHOOK_SECRET=…
BOOKING_TOKEN_AMOUNT=2000   BOOKING_HOLD_DAYS=3

# whatsapp (BSP)
WHATSAPP_PROVIDER=aisensy      # aisensy | gupshup | twilio | interakt | console
WHATSAPP_API_KEY=…  WHATSAPP_SENDER_ID=…  WHATSAPP_WEBHOOK_SECRET=…

# sms / email / esign / maps / sentry
SMS_PROVIDER=msg91  SMS_API_KEY=…
EMAIL_URL=…  DEFAULT_FROM_EMAIL=…
ESIGN_PROVIDER=digio  ESIGN_CLIENT_ID=…  ESIGN_CLIENT_SECRET=…
MAPS_API_KEY=…  SENTRY_DSN=…

# frontend (per app)
VITE_API_BASE_URL=…  VITE_RAZORPAY_KEY_ID=…  VITE_MAPS_TOKEN=…  VITE_SENTRY_DSN=…
12

Roadmap

Phased so a usable, revenue-affecting slice — automated billing + WhatsApp reminders + payments — ships first, then breadth. Durations assume ~1–2 backend + 1 frontend engineer.

P0Foundations2–3 weeks
  • Monorepo, CI, Docker Compose, environments, Sentry.
  • Django + Postgres + Redis + Celery + Beat + object storage.
  • Auth: staff login + 2FA, tenant phone-OTP, RBAC + property scoping, audit log.
  • Organization / Settings / encrypted IntegrationCredentials with test buttons.
  • Property / Unit / Bed / Amenity / Meter models + dashboard shell + Properties CRUD with photo upload.
  • OpenAPI schema → generated TS client; seed/demo data command.
P1MVP — list → enquire → onboard → bill → collect5–7 weeks
  • Public website: landing, search + filters, listing & property pages, enquiry form, WhatsApp click-to-chat, SSR/SEO, sitemap.
  • Leads: capture, pipeline, assignment, auto enquiry_ack, convert-to-onboarding.
  • Onboarding: application + KYC + terms + unit assignment + welcome (agreement = signed-scan upload for now).
  • Billing: charge types, recurring charges, daily billing run (rent + recurring + sub-meter / fixed electricity + water), numbering, invoice PDF, tenant + deposit ledger, ad-hoc invoices.
  • Payments: Razorpay Payment Links, webhook reconciliation, receipt PDF, offline entry + approval, partial payments + allocation.
  • WhatsApp: BSP adapter + console provider, template registry, scheduler, P1 templates, cadence T−3 / T0 / T+1, payment_received, delivery tracking.
  • Dashboard home KPIs; tenant portal P1 (OTP, dues + pay, invoices, receipts, ledger, tickets); reports: rent roll, occupancy, collections.
P2Depth — automation, agreements, maintenance, self-service5–7 weeks
  • Proration, late-fee engine, credit notes with approvals, shared-meter split, full cadence with escalation, aging report.
  • UPI Autopay, promise-to-pay, deposit refund via Payout, reconciliation view.
  • Agreement templates + e-sign + versioning + police-verification form.
  • Rent escalation, renewal workflow + expiry reminders, notice → move-out settlement, transfers, move-in/out inspections.
  • Maintenance tickets (portal + WhatsApp), vendors, SLA, preventive schedules.
  • Two-way WhatsApp, keyword auto-replies, staff inbox, broadcasts, channel fallback, opt-out + quiet hours + cost logging.
  • Tenant portal P2; website schedule-a-visit + book-now token + reviews; reports P2 + scheduled digests; cadence & template editors.
P3Growth — finance, analytics, content4–6 weeks
  • Expenses, owner payouts, per-property P&L, cash-flow, Tally / Zoho exports, GST report.
  • Asset register; churn / retention & maintenance-cost analytics; richer dashboard charts.
  • Public-site CMS-lite, locality SEO pages, English / Hindi, blog.
  • Tenant portal P3 (PG roommate + mess, refer-a-friend, PWA, push); electricity slabs; convenience-fee pass-through.
P4Advanced / optionalongoing
  • React Native apps; channel manager; smart access & IoT meters; AI (chatbot, default-risk scoring, ticket triage, OCR).
  • Aadhaar / DigiLocker KYC; mess & laundry; short-stay mode; renter's insurance; BBPS; multi-owner SaaS.

First three demo milestones

  1. M1 (end P0) — manage properties & units with photos; see them listed.
  2. M2 (mid P1) — website search + listing detail + enquiry → lead in the dashboard → enquiry_ack on WhatsApp.
  3. M3 (end P1) — onboard a tenant → billing run creates an invoice → WhatsApp bill with a Razorpay link → pay → auto-reconcile → receipt on WhatsApp → dashboard shows the collection.
13

Initial setup

Local development brings up Postgres, Redis, MinIO (S3) and MailHog in Docker; the API, worker and Beat run on the host.

# one-time
cp .env.example .env
docker compose -f infra/docker-compose.yml up -d db redis minio mailhog

# backend
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements/dev.txt
python manage.py migrate
python manage.py seed_demo          # demo org, properties, units, a tenant, invoices
python manage.py runserver
celery -A config worker -l info
celery -A config beat -l info

# frontend
cd ../frontend
pnpm install
pnpm --filter website dev           # public site  :3000
pnpm --filter dashboard dev         # admin        :5173
pnpm --filter portal dev            # tenant       :5174
pnpm --filter api-client generate   # regenerate the TS client from the backend OpenAPI

Services & ports

ServiceURL
APIlocalhost:8000 · schema at /api/schema/ · docs at /api/docs/
Admin dashboardlocalhost:5173
Tenant portallocalhost:5174
Public websitelocalhost:3000
MailHoglocalhost:8025
MinIO consolelocalhost:9001

Webhooks in development

Run an ngrok / cloudflared tunnel to :8000 and point the Razorpay and BSP sandbox webhooks at it. Use Razorpay test mode and the console WhatsApp provider to avoid real charges and sends; POST /messages/test sends any template to a chosen number for QA.

Reading order for the full spec

This page consolidates the Markdown specification in /docs: 01 product overview · 02 feature catalogue · 03 roles & permissions · 04 architecture · 05 data model · 06 API design · 07 WhatsApp automation · 08 billing & payments · 09 admin dashboard · 10 public website · 11 tenant portal · 12 tech stack · 13 non-functional requirements · 14 roadmap · 15 glossary.