# Ooru — Notes & Reference

> Saved record of the codebase audit (2026-06-09) and the bengaluru.rent competitive
> analysis. This is the durable context file. CLAUDE.md / AGENTS.md point here.
> Authored under maahaa.dev. Last updated 2026-06-09.

> **Current direction — v2 (PocketBase).** The architecture verdict is to migrate v1 →
> the og-coach PocketBase pattern (one binary + one `pb_hooks/main.pb.js` hook +
> `pb_migrations/` + a vanilla `pb_public/` PWA + `tools/deploy.sh`). Full plan:
> `docs/MIGRATION.md`; visual: `docs/architecture.html` §04. This makes the two worst v1
> bugs impossible by construction — fabrication (one linear hook passes only verified
> fields; no node `return {}` to drop schools/metro) and the hardcoded JWT secret
> (PocketBase auth replaces the hand-rolled auth). v2 is NOT built yet; v1 still runs.
> The audit below describes v1 — it's the thing being migrated away from, kept as the
> reference the migration is built against. The §8 Horizon-0 fix-list assumed an in-place
> v1 repair; under v2 most of it (0.1 fabrication, 0.2 JWT, 0.4 dead code) is resolved by
> the rewrite rather than patched — see the note at §8.

---

## 1. What Ooru is

> Name: **Ooru** (ಊರು) — Kannada for "one's own place / town / where you belong."
> Bangalore-native, true to a tool that judges where you'd live. Domain: ooru.maahaa.dev.
> Renamed from "hh-ref" 2026-06-09. On-disk repo folder also renamed to `ooru/`
> (was `hh-ref/`); git history preserved (plain dir move, .git travels with it).
> Docs use relative paths, so no path edits were needed. Path now:
> /Users/sushil/SS_WRK/househunter/ooru/

Bangalore house-hunting assistant. A user enters a landmark; the system geocodes it,
finds nearby metro stations and ICSE schools, ranks alternative localities by air
quality (AQI), (intends to) scrape rental listings, then an LLM (Moonshot Kimi K2.6)
writes a "premium advisory report."

Two surfaces:
- CLI — `chatbot.py` + `workflow.py` (interactive terminal)
- API — `backend/app.py` (FastAPI: register / token / login / chat / history)

Maturity: early MVP. 2 git commits. No README (until these docs), no migrations, no CI,
no Dockerfile, no .gitignore.

## 2. Tech stack (confirmed)

- FastAPI — REST + auth
- SQLAlchemy — ORM, models + API-response cache (NOT Prisma)
- LangGraph — orchestrates data-gathering as a node graph
- OpenAI SDK → Moonshot Kimi K2.6 — LLM advisory, with hardcoded simulation fallback
- External APIs: Mapbox (geocoding v5 + matrix), Foursquare Places (metro/schools),
  Open-Meteo (AQI), Apify (housing.com scraping)
- Auth: JWT (python-jose) + bcrypt (passlib)
- DB: per `DATABASE_URL` (JSON columns imply Postgres)

## 3. Data model (SQLAlchemy, in backend/database.py)

    User (1) ──< (N) HouseRental
      User:        id, username, email, password_hash
      HouseRental: id, user_id(FK,nullable), user_location,
                   top_matches(JSON), top_matches_coordinates(JSON)
    APICache (standalone): id, api_name, cache_key(unique), response_data(JSON), created_at

Data flow (real):
  landmark → POST /chat (JWT) → execute_chat_workflow() → workflow_app.invoke() (LangGraph)
    GET_LOCATION_AND_LOCALITY (Mapbox geocode, cached)
    FIND_NEARBY_SCHOOLS  (Foursquare ICSE — PRINTS ONLY, discarded)
    FIND_NEARBY_PLACES   (Foursquare metro — PRINTS ONLY, discarded)
    GET_AQI              (Open-Meteo target, cached)
    RANK_BY_AQI          (Open-Meteo per locality → sorted ascending)
  → Kimi advisory (or simulation) → save_house_rental() → ChatResponse
  GET /history → all HouseRental rows for current user.

## 4. Audit findings (2026-06-09, re-verified in code)

### Works well
- LangGraph decomposition is clean (thin node wrappers, parallel schools+places edges).
- APICache layer cuts cost/latency, keyed sensibly. Good instinct.
- Foursquare has a real fallback (ask → geotagging/candidates).
- LLM degrades gracefully to simulation.
- Auth basics: bcrypt, JWT, login by username OR email.

### Critical — data honesty (THE #1 issue)
- `node_find_nearby_schools` / `node_find_nearby_places` (workflow.py:33-52) both
  `return {}`. Foursquare results only print to console; never enter GraphState.
- LLM prompt (services.py:139-146) contains ONLY coords + AQI + ranked localities.
  Schools and metro are NOT in the prompt.
- Simulation fallback (chatbot.py:31-39) hardcodes school/metro praise as static text.
- NET: every "ICSE schools nearby" / "metro under 3km" claim in the report is
  FABRICATED, independent of actual API results. Shipping-blocker.

### Other code-quality issues
- Dead/duplicate: backend/schemas.py is entirely unused (duplicates models.py).
  models.py is misnamed (holds schemas; database.py holds the actual models).
- Broken node: workflow.py:76 calls house_rental_apify(ranked) but main.py:247 defines
  house_rental_apify() with NO params and a hardcoded single housing.com URL. The node
  is commented out (workflow.py:88,98) so it doesn't crash — Apify is non-functional.
- get_travel_times (main.py:171) defined, never called. Dead.
- main.py:75 reads `context` but never uses it.
- print()-driven logic throughout main.py; functions return None on no-result paths.
- No timeouts on ANY requests.get() call — a hung API hangs the whole request.
- Duplicated login logic (/token vs /login in app.py); duplicated price-parse in
  chatbot.py and workflow.py.
- /chat is fully synchronous, multi-second, no streaming/progress.
- UserRegister.email is plain str (not EmailStr) — no validation.

### Security
- JWT SECRET_KEY defaults to hardcoded literal "house-hunt-secret-key-1234567890"
  (services.py:22). Anyone can forge tokens. Must require env, no default.
- .env committed to repo (in git ls-files). Keys likely leaked into history. ROTATE.
- __pycache__ committed (git ls-files shows .pyc). Need .gitignore.
- No CORS, no rate limiting, no password strength, no email verification.
- HouseRental.user_id nullable → orphan rows possible.

### Missing best practices
- No Alembic; init_db() does create_all() at import time (database.py:94) — side-effecting.
- Tests not pytest-structured (bare asserts, __main__ runners). test_api hits LIVE
  external APIs + real DB + needs cached "Indiranagar". Not hermetic, no mocking.
- No README/Dockerfile/.gitignore, unpinned requirements.txt (no versions), no logging.
- sys.path.append hack in services.py:13 — missing package structure (no __init__.py).

### Outdated / improvements
- requirements.txt fully unpinned — biggest reproducibility risk.
- Mapbox geocoding v5 (main.py:17) is the legacy endpoint (Search Box API is current).
- python-jose effectively unmaintained — consider PyJWT/authlib.
- Hardcoded Bangalore bbox/proximity (main.py:22-23) — single-city only.
- Synchronous requests in async-capable FastAPI — consider httpx + async.

## 5. Competitor — bengaluru.rent (verified live 2026-06-09)

Anonymous, crowdsourced rent map for Bangalore. No login/signup/app.
Tagline: "Real Bangalore rents — anonymously shared by actual renters."
Mission: "make Bangalore rental data as transparent as it should be." Founder: Harshit Anand.

Live stats (today): 97k+ visitors · 4,764 real rents pinned · ₹235 Cr+ on map ·
449 active flat-hunters · 114 owner-direct flats · 931 watchlisted · 2,285 matches made.

Three pin types (confirmed from live DOM forms):
- Rent report: BHK + rent + ★rating + comment + "report fake/wrong location" (crowd fact-check).
- Lister (owner-direct): BHK, sqft, society name, rent, "whole available", email/phone. Zero brokerage.
- Seeker: budget Min/Max, BHK, email/phone, + lifestyle freetext (flatmate matching angle).

Matching: drop seeker pin → email when listings within 2.5km match budget/BHK. 2,285 matched.
Map features: Green Cover (Sentinel-2 satellite), Satellite toggle, Hide pins, Metro overlay
(Namma Metro lines), Area stats, Find my location, "Near Metro" filter, NL filter textarea
("filter by distance from my office"), watchlist (email + area → ping).

Tech: Google Maps JavaScript API v3 (maps.googleapis.com, .gm-style present —
NOT Mapbox, NOT Leaflet). AdSense-funded (ca-pub-6301387373948316). Backend implied =
simple geo CRUD for pins + email-match queue. Scales cheaply (UGC, stateless, no accounts).

Honest weaknesses:
- Zero quantitative livability analysis: no AQI numbers, no school data, no commute math.
- No reasoning/narrative — raw pins + filters only.
- No accounts → no saved searches, history, or personalized comparison.
- No API / programmatic access.
- Data quality depends on crowd; long-tail coverage sparse (many "2 flats" cells).
- No ICSE/CBSE school signal at all (a top family/buyer concern).

## 6. Strategic verdict

Ooru and bengaluru.rent compete on opposite axes. bengaluru.rent's moat = real
community rent data + zero friction. Ooru's moat = authenticated, AI-reasoned,
multi-signal locality intelligence (AQI + schools + metro + LLM advisory).

Do NOT clone their map. DIFFERENTIATE as the decision-support / "why this locality"
layer. Trending to HYBRID later (a thin map VIEW of ranked localities, not a pin-drop
competitor) once trust is restored.

The honesty fix is the gate. Until schools/metro data is real in the report, Ooru is
LESS trustworthy than a competitor with zero analysis — because it asserts findings it
never computed. Fix that first.

## 7. Positioning (recommended)

> Ooru is the AI locality-intelligence engine for Bangalore house hunters. Map tools
> like bengaluru.rent show you WHERE people rent; Ooru tells you WHY a locality is a
> smart choice — combining real AQI, verified school proximity, and metro access into a
> reasoned, personalized advisory you can trust and revisit.

## 8. Roadmap (horizons)

> **v2 note:** this Horizon-0 list was written for an in-place v1 repair. The chosen path
> is the v2 PocketBase rewrite (docs/MIGRATION.md), which resolves 0.1 (fabrication) and
> 0.2 (JWT secret) by construction and makes 0.4 (delete dead v1 files) moot — those files
> are dropped wholesale. 0.3 (.gitignore + rotate leaked keys) and 0.6 (pin deps) still
> apply regardless. Horizons 1–2 (map view, livability score, commute, personal KB) carry
> over to v2 unchanged — they're product features, not stack-specific. Read this list as
> "what was broken in v1 + what to build," then implement via MIGRATION.md.

### Horizon 0 — Trust & hygiene (do first)
| # | Action | Files | Effort | Risk |
|---|---|---|---|---|
| 0.1 | Wire schools+metro into GraphState + LLM prompt + persist (THE honesty fix) | main.py, workflow.py, services.py, chatbot.py | M | low |
| 0.2 | Remove hardcoded JWT secret default; require env, raise if missing; rotate | services.py:22 | S | low |
| 0.3 | Add .gitignore; untrack .env + __pycache__; rotate leaked keys | repo root | S | low |
| 0.4 | Delete dead code: schemas.py, get_travel_times, unused context var | backend/schemas.py, main.py | S | low |
| 0.5 | Add timeout= to all requests.get (6 spots) | main.py | S | low |
| 0.6 | Pin requirements.txt versions | requirements.txt | S | low |
| 0.7 | Make /chat non-blocking OR add progress (LangGraph streaming / async) | app.py, services.py | M | med |

### Horizon 1 — Parity + differentiation (2-4 wks)
- Fix/replace rentals data path (dynamic Apify URL, or public price ranges). High / M.
- Map view of ranked localities. Mapbox GL (reuse existing token, recommended). High / M.
- Enrich LLM prompt with real structured data (school count/dist, metro, per-locality AQI,
  rent range). High / S.
- Comparison endpoint for 2+ saved HouseRentals. Medium / S.

### Horizon 2 — Moat (what they can't do)
- Multi-signal livability score (AQI + school dist + metro time + green-cover proxy). High / M.
- "What-if" commute modeling (reuse dead get_travel_times as a real node). High / M.
- Personal knowledge base (notes per locality, saved reports). Medium / M.
- Opt-in crowdsourced rent signals (authenticated) — only AFTER trust restored. Medium / L.

## 9. Single highest-leverage next step

0.1 — wire real schools + metro into GraphState and the LLM prompt (and persist it).
Cheapest fix, biggest payoff: removes the fabricated-findings problem AND activates
schools/metro as honest differentiators bengaluru.rent doesn't have. Bundle 0.2/0.3/0.5
(secret + .gitignore + timeouts) in the same pass — a few lines each, real risk reduction.

## 10. Installed design skills (in .agents/skills/)

hallmark (anti-AI-slop design), impeccable (design context; run `/impeccable init` in
harness), + taste-skill set: high-end-visual-design, design-taste-frontend (+v1),
minimalist-ui, gpt-taste, industrial-brutalist-ui, brandkit, stitch-design-taste,
redesign-existing-projects, image-to-code, imagegen-frontend-web/mobile,
full-output-enforcement. All scanned Low Risk. They live INSIDE the repo — add
.agents/ .claude/ .cursor/ .gemini/ .opencode/ to .gitignore (ties into 0.3).

Design system for maahaa.dev-authored artifacts: Cosmic Engineering
(~/SS_WRK/maahaadev/Design System/). Dark cosmic-ink ground, saffron single accent,
Fraunces / Outfit / JetBrains Mono, atmosphere layers, vibhuti mark. NO emoji.
