Skip to content
Ritesh FirodiyaGet in touch

Work / DwarSeva Property / Wiki / Concepts

non-functional

Conceptcanonicalverified 2026-07-22

CONCEPT.NON-FUNCTIONAL

Non-functional — Regulatory, SLOs, observability, cost, open questions

The constraints that shape the architecture even though they're not user-facing. Regulatory context in ../product/regulatory.md.


Regulatory constraints (architectural implications)

PPI compliance (RBI, via Razorpay)

Rule: don't hold customer wallet balance long. Closed-loop PPI without a license is risky if balance sits.

Implication

  • Weekly cron sweeps wallets with balance > 0 AND last_activity < now() - 60d; sends a "use it or we refund" nudge.
  • Wallets untouched for 90 days are auto-refunded to the original source (Razorpay refund API), balance zeroed, wallet_ledger entry reason='ppi_auto_refund'.
  • Ledger row cap per user: soft limit 10 000 rows before archival. Long-lived users don't hit this at ₹5 units.

DPDP Act 2023 (effective May 2027)

Rule: explicit consent per purpose, purpose limitation, data minimisation, breach notification, deletion-on-request, DPO if scaled.

Implication

  • Every table with PII carries consent_purposes text[] and created_at — enforced at the Drizzle schema layer.
  • DELETE /me endpoint cascades to soft-anonymise (name, phone hashed; wallet ledger retained with user_id nulled — needed for accounting).
  • Photo retention: 30 days past listing.state='removed_by_admin' OR sold_or_rented, then hard-deleted by a cron. Buyer's unlocked contacts survive as unlocks rows (anonymised owner) for audit.
  • Breach notification: any auth-log anomaly emits a Sentry event tagged dpdp:breach-suspect and pages the DPO email within 72 hours.

RERA (per state; capture-only at MVP)

Rule: agents and builders need registration; individual owner rentals mostly exempt.

Implication

  • agent_nocs table with rera_agent_no, noc_url, verified_at. Populated for seller_agent role only.
  • Reviewer UI (A03) surfaces RERA number and validates format per state (regex table in packages/schema/rera.ts).
  • Commercial listings: reviewer must attach state RERA project ID or explicitly flag "under 8 units, exempt" before approve.

IT Rules 2021 (grievance)

Rule: 72-hour acknowledgement, named Grievance Officer, published contact.

Implication

  • POST /complaints auto-sends a template email from grievance@dwarseva.in within 60 seconds of file.
  • Public /grievance route on apps/web — no auth wall.
  • All grievance-officer email replies are archived in R2 under /grievance/<complaint_id>/.

GST

Rule: invoice per wallet top-up over ₹0.

Implication

  • Every Razorpay-webhook-triggered credit generates a PDF invoice and mails to the user's email (email required before first recharge — CATALOG § Identity/KYC).
  • Invoice numbering is monotonic per financial year — enforced by a Postgres sequence with a year prefix.

SLOs

Startup MVP scale. Numbers to defend, not to worship.

Surface Target Measurement
apps/web P50 TTFB < 300 ms Vercel Analytics / Sentry web-vitals
apps/api P50 latency < 50 ms Cloudflare Workers Analytics + Sentry
apps/api P99 latency < 400 ms same
Wallet debit correctness 100% (zero drift) weekly reconciliation cron
Verification queue SLA 48 h (CATALOG) dashboard on A01, alert if backlog > 20 with oldest > 48 h
Complaint ack < 72 h dashboard + auto-page
Availability 99.5% monthly (~3.6 h/month) Better Stack uptime

Deliberately not chased at MVP: five-nines availability, sub-100ms P99, real-time everything. These are Phase 3+ concerns.


Observability

Signal Tool Free tier ceiling Alert channel
Errors + traces (all surfaces) Sentry 5 K events/mo Slack + email
Product analytics PostHog Cloud 1 M events/mo dashboard only
Logs (structured JSON) Better Stack 3 GB/mo Slack
Uptime + on-call Better Stack 10 monitors Slack + phone (paid tier)
Wallet reconciliation Custom cron in apps/api; posts to Sentry as wallet:drift if sum(ledger.delta) != wallet.balance for any user n/a pager

Trace propagation

  • Sentry trace_id is generated at apps/web / apps/mobile and forwarded as sentry-trace header on every API call.
  • apps/api continues the trace and attaches DB spans via Drizzle instrumentation.
  • Queue jobs restart the trace by attaching the parent trace_id from the enqueue site.

Cost ceilings (architectural budget)

If any subsystem approaches its ceiling, we redesign the subsystem, not raise the ceiling.

Item MVP ceiling Reason
Total infra ₹5 000 / month Startup budget while validating
Cloudflare Workers 10 M req/mo → $5 Should cover 10 K MAU; if not, product-market fit is wrong shape
Neon Postgres 10 GB DB, $19/mo Pro Beyond this, archive listings older than 12 months to R2 (JSON dump)
R2 storage 1 TB → ~$15 Photo pipeline resizes and re-encodes to AVIF; each listing < 5 MB total
MSG91 OTP ₹0.15 × 30 000 OTPs = ₹4 500 1 OTP per sign-in / phone change. If we exceed 30 K/mo we have real traffic; move the discussion.
WhatsApp (AiSensy) ~$25 starter tier Beyond this, batch notifications instead of per-event

Open questions (block or shape step 4)

  1. Mobile map performance — does MapLibre native (@maplibre/maplibre-react-native) render 18 polygons + labels smoothly on mid-tier Android? Test before locking. Fallback: WebView + MapLibre GL JS.
  2. Reverse-image-search vendor — TinEye API ($200/mo starter), self-hosted CLIP embeddings (free but adds a worker), or Google Vision (pay-per-call, expensive at volume). Decide in step 6.
  3. Queue-worker cold start — Cloudflare Queues + Workers have a small warm-up cost. Confirm that photo-resize p99 < 30 s end-to-end (upload → resized variants visible). If not, split into a dedicated Cloud Run worker.
  4. RERA capture UX per state — each state's format differs. Decision: MVP validates only the four biggest (MH, KA, TN, DL) with regex; other states accept free-text with reviewer eyeball check. Revisit at 5-state scale.
  5. Session strategy on apps/web — HttpOnly cookie set by Supabase Auth server helper on server actions vs bearer-token in-memory. Decision leaning toward cookie for web; bearer + SecureStore for mobile. Confirm in step 4.
  6. Which Supabase Auth region — Mumbai (ap-south-1) preferred for latency; verify Supabase supports it on the tier we pick.
  7. Turnstile or hCaptcha on OTP request? MSG91 gets abused if we don't rate-limit. Cloudflare Turnstile is free and works well; recommend, decide in step 4.

Each item should be closed (decision + one-line rationale) before step 5 begins.

Every project of mine is written down like this.

Read the résumé