This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
DealLens — real estate underwriting platform. 120-month DCF engine calibrated against industry-standard Excel proformas. Two validated reference deals: Maple Avenue (10.99% IRR) and Riverside Crossing (12.04% IRR).
# Dev server (port 8001 — do NOT use 8000, reserved for other services)
uvicorn app.main:app --reload --port 8001
# All tests (25 unit pass, 8 integration need live Supabase JWT)
python3 -m pytest tests/ -v
# Unit tests only (skip integration)
python3 -m pytest tests/ -v --ignore=tests/test_integration.py
# Single test file
python3 -m pytest tests/test_validation_regression.py -v
# Single test
python3 -m pytest tests/test_validation_regression.py::test_riverside_regression -v
# Docker
docker build -t deallens-backend . && docker run -p 8001:8000 deallens-backendnpm run dev # port 3000
npm run build # Turbopack
npm run lintorchestrator.py is the entry point. build_120_month_cash_flow(ProformaModel) calls services in this order:
- budget.py — land + soft + hard + financing cost aggregation →
total_budget - calculations.py —
calculate_egi()andcalculate_opex()from rent roll → stabilized NOI - loans.py —
calculate_construction_loan(),calculate_permanent_loan(),calculate_mezzanine_loan()— constraint-based sizing (LTV/LTC/DSCR/DebtYield),lender_quoted_amountoverrides sizing - 120-month loop: monthly EGI/OpEx with growth + vacancy ramp, S-curve construction draws, construction interest accrual, perm loan funding at stabilization (pays off construction + mezz), IO→amortizing perm debt service, sale proceeds at exit
- GP/LP waterfall — 2-tier return-of-capital structure using
PromoteStructure.hurdles(Tier 1 = first active hurdle splits, Tier 2 = last active hurdle splits, fallback = equity split) - Annual rollup → cash_flow.py for statement + returns.py for XIRR/equity multiple
All routes in app/api/routes/deals.py, prefixed /api/v1/deals. Auth via get_current_user (JWT decode) and get_supabase (RLS-enforced client) dependency injection.
| Endpoint | Purpose |
|---|---|
POST / |
Create deal |
GET / |
List user's deals (RLS filtered) |
GET /{id} |
Get deal |
POST /{id}/calculate |
Run engine (rate limited: 10/min) |
GET /{id}/viability |
Viability flags only |
DELETE /{id} |
Soft delete (status='deleted') |
Next.js App Router. (auth)/login for Supabase auth, (app)/ for protected routes. lib/api.ts injects Bearer token from Supabase session. Results page calls /calculate live on every load.
app/models/proforma.py contains the full input schema:
ProformaModel→DashboardInputs(150+ fields) +RentRollInputDashboardInputscontainsBudgetInputs,DebtAssumptions(x3: construction, permanent, mezzanine),PhaseTimeline[],PromoteStructure→PromoteHurdle[]@model_validator(mode='before')merges legacyassumptionsblock intodashboard
- Regression tests (
test_validation_regression.py): assertproject_irrfor both reference deals. Dual-deal rule — no engine change valid unless both pass. - Maple Avenue payload: imported via
get_exact_maple_avenue_proforma()fromtest_payloads.py - Riverside Crossing payload: imported as
p_datafromriverside_payload.py - Integration tests (
test_integration.py) require live Supabase — expect 401s locally
Backend .env:
SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_JWT_SECRET
Frontend .env.local:
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, NEXT_PUBLIC_API_URL=http://localhost:8001
- Python: async def routes, Pydantic v2 models, type hints, dependency injection
- Conventional commits:
feat:,fix:,docs:,refactor: - Never commit to main directly — always branch
- Supabase RLS enforces multi-tenancy; never bypass with service key in app code
- Soft deletes only — database blocks physical DELETE to protect audit trail
python3notpython(macOS)
Use sub-agents with cheaper models for simple tasks. Opus is expensive — reserve it for reasoning-heavy work.
Use Sonnet sub-agents for:
- File reads and grep searches
- Running tests and capturing output
- Formatting, linting, import sorting
- Writing or updating documentation and comments
- Simple find-and-replace edits where the change is obvious
- Git operations (commit, branch, diff, log)
- Generating boilerplate code from clear specs
- CSS/styling tweaks
Keep on Opus for:
- Engine logic changes (orchestrator, loans, returns, cash_flow)
- Debugging failing tests where root cause is unclear
- Architectural decisions and multi-file refactors
- Anything touching IRR, waterfall, or debt sizing calculations
- Root cause classification (Bucket 1/2/3 analysis)
- Planning and verification protocols
General rules:
- Parallelize independent sub-tasks when possible
- Batch file reads into single operations instead of sequential calls
- When running verification (pytest + live API checks), delegate the execution to a sub-agent and review results
- Never use Opus tokens just to read a file and report its contents