Remodel/CODEBASE_INVESTIGATION.md
Mannu e6dc39aa33 [S1-T12/T13] P&L revenue breakdown + collapsible rows + UI polish
- Engine: Add ppa_revenue_cr, mcp_revenue_cr, tariff, units to PnLRow
- Engine: Split PPA vs MCP revenue in P&L computation
- Web: Collapsible rows for PPA/MCP Revenue and Opex
- Web: Highlighted rows (Total Revenue, EBITDA, EBIT, PBT, PAT)
- Web: Units above Tariff in breakdown, bg-blue-50 highlight
- Fix sticky column z-index for horizontal scroll
- CLAUDE.md: Add project documentation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 10:42:36 +05:30

20 KiB
Raw Permalink Blame History

REmodel Codebase Investigation Report

Date: 2026-05-07
Investigator: Claude (Agentic exploration)


1. Executive Summary

REmodel is a full-stack hybrid renewable energy (Solar + Wind + BESS) project finance modeling platform built in Python with a FastAPI backend and Next.js frontend. The project is designed to replace an Excel-macro workflow used for bid preparation at ReNew Power in India, targeting computation of optimal flat tariff and full 25-year project financials in under 30 seconds per scenario.

Key Architecture

┌─────────────────────────────────────────────────────────────────────────┐
│                      packages/engine                     │
│  Python calculation engine (pip-installable)           │
│  • Generation (solar, wind, BESS)                     │
│  • Capex + IDC calculation                            │
│  • Financial model (P&L, CFS, BS)                    │
│  • Debt sizing + scheduling                          │
│  • Tariff solver (brentq)                          │
│  • CLI driver (Typer)                             │
└─────────────────────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                       packages/api                     │
│  FastAPI + Arq async workers (Redis-backed)            │
│  • REST endpoints (scenarios, templates)           │
│  • Background task processing                    │
│  • SQLite + Parquet storage                     │
│  • SSE for real-time progress                   │
│  • Excel export                                 │
└─────────────────────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                       packages/web                    │
│  Next.js 14 App Router + shadcn/ui + Tailwind    │
│  • Scenario list + wizard                       │
│  • Results dashboard                           │
│  • KPI visualizations (Recharts)              │
│  • Compare scenarios view                     │
│  • DataGrid (AG Grid)                        │
└─────────────────────────────────────────────┘

2. Codebase Structure

2.1 Root Directory

/Users/manohar_air/MyProjects/REModel/
├── PROJECT.md               # Master specification document
├── README.md              # Quick reference
├── docker-compose.yml     # Redis service
├── Makefile             # Common commands
├── .pre-commit-config.yaml
├── .github/workflows/  # CI/CD
├── packages/           # Monorepo structure
│   ├── engine/        # Python calculation engine
│   ├── api/          # FastAPI backend
│   └── web/          # Next.js frontend
└── sprints/           # Sprint documentation (SPRINT_00-08)

3. Packages/Engine Analysis

3.1 Module Structure (42 Python files)

packages/engine/src/remodel_engine/
├── __init__.py
├── cli.py                  # Typer CLI (simulate-gen, compute-idc, solve-tariff)
│
├── schemas/               # Pydantic models (single source of truth)
│   ├── __init__.py
│   ├── scenario.py        # ScenarioInput, ScenarioResult, KpiSummary
│   ├── capex.py         # CostItem, CapexConfig, PhasingCurve, DrawdownCurve
│   ├── debt.py          # DebtConfig, DebtYearRow, IRRMetrics
│   ├── financial.py     # CommercialConfig, OpexConfig, TaxConfig, Financials
│   └── generation.py    # SolarConfig, WindConfig, BessConfig
│
├── catalog/             # Defaults and profile loaders
│   ├── __init__.py
│   ├── defaults.py      # Constants: PROJECT_LIFE=25, HOURS=8760
│   ├── loader.py     # Solar/wind profile CSV loader (RJ, KA, GJ)
│   └── profiles/    # Bundled 8760-hour CSV files
│
├── generation/        # 25-year generation simulation
│   ├── __init__.py
│   ├── solar.py      # DC→AC→clipping→availability→soiling→degradation
│   ├── wind.py      # Power curve lookup→shear→wake→availability
│   └── bess_state.py # Degradation + augmentation capacity model
│
├── dispatch/         # Hybrid RTC dispatch
│   ├── __init__.py
│   ├── hybrid_rtc.py # Per-hour charge/discharge logic
│   └── mcp_settlement.py # Merchant sale at MCP
│
├── capex/          # Capital expenditure
│   ├── __init__.py
│   ├── cost_items.py # CostItem catalog → total capex
│   ├── phasing.py   # Construction phasing matrix
│   └── idc.py      # Interest During Construction (fixed-point)
│
├── commercial/     # Revenue and DSM
│   ├── __init__.py
│   └── ppa.py      # Generation aggregation, receivables/payables
│
├── financial/      # 3-statement model
│   ├── __init__.py
│   ├── pnl.py      # Revenue → OpEx → EBITDA → Depr → EBIT → Tax → PAT
│   ├── cfs.py     # Cash Flow Statement (CFO/CFI/CFF)
│   ├── bs.py      # Balance Sheet (reconciliation)
│   ├── depreciation.py # Book SLM + tax WDV schedules
│   ├── tax.py     # 115BAA (India) tax computation
│   └── working_capital.py # Receivables, payables, inventory
│
├── debt/          # Debt financing
│   ├── __init__.py
│   ├── sizing.py  # Fixed-point debt sizing (D:E, DSCR constraints)
│   └── schedule.py # Repayment shapes (equal principal, EMI, sculpted, balloon)
│
├── irr/           # Financial metrics
│   └── metrics.py # IRR, NPV, LCOE, DSCR, LLCR, PLCR, payback
│
├── solver/        # Solver logic
│   └── tariff.py # Brentq solver for tariff→IRR target
│
├── scenarios/     # Scenario orchestration
│   ├── __init__.py
│   ├── runner.py  # Full pipeline (generation→financial→debt→IRR)
│   └── sweep.py  # Sensitivity analysis
│
└── io/          # Data export
    └── excel_export.py # .xlsx workbook generation

3.2 Key Schema Definitions

ScenarioInput (Top-level input)

class ScenarioInput(BaseModel):
    project: ProjectInfo           # name, state, capacities, COD
    solar: SolarConfig | None   # location, DC/AC, losses, degradation
    wind: WindConfig | None    # location, MW, hub-height
    bess: BessConfig | None   # MWh, power, RTE, DoD
    rtc: RtcConfig | None     # contracted RTC MW, MCP toggle
    commercial: CommercialConfig # tariff, losses, working capital
    capex: CapexConfig       # cost items, phasing curves, drawdowns
    opex: OpexConfig        # O&M, insurance, land lease
    debt: DebtConfig        # rate, tenor, DSCR constraints
    tax: TaxConfig         # 115BAA rates
    solver: SolverConfig    # solve_tariff or fixed_tariff mode

ScenarioResult (Full output)

class ScenarioResult(BaseModel):
    inputs: ScenarioInput
    status: Literal["queued","running","success","failed"]
    solved_tariff: float | None
    kpis: KpiSummary          # equity_irr, project_irr, DSCR, capex, LCOE, etc.
    financials: Financials    # pnl_25y, cfs_25y, bs_25y
    debt_schedule: list[DebtYearRow]
    irr_metrics: IRRMetrics
    warnings: list[str]
    runtime_s: float
    generation_by_year: list[dict]
    idc_phasing: dict

3.3 Financial Model Flow

The 3-statement model computes:

  1. P&L (Profit & Loss)

    • Revenue: generation_MWh × tariff × (1 - losses) / 10^7 → Cr
    • OpEx: O&M + insurance + land_lease + AM_fee + misc
    • EBITDA = Revenue - OpEx
    • Depreciation: Book SLM by asset class
    • EBIT = EBITDA - Depreciation
    • Interest: From debt schedule
    • PBT = EBIT - Interest
    • Tax: 115BAA (25.17%) current + deferred
    • PAT = PBT - Tax
  2. CFS (Cash Flow Statement)

    • CFO = PAT + Depreciation - ΔWC
    • CFI = 0 (capex in year 0)
    • CFF = Debt drawdown - Debt repayment + Equity injection
    • Net = CFO + CFI + CFF
  3. BS (Balance Sheet)

    • Assets = Net block + Cash + Receivables
    • Liabilities = Equity + Reserves + LT Debt + Payables + DTL
    • Reconciliation enforced (≤₹0.05 Cr difference)

3.4 Debt Sizing Algorithm

The debt sizing module (debt/sizing.py) implements a fixed-point iteration that satisfies three constraints:

  1. D:E Ratio Cap: debt ≤ total_capex × de_ratio / (1 + de_ratio)
  2. Min DSCR Constraint: debt ≤ max satisfying min(DSCR) ≥ min_dscr
  3. Avg DSCR Constraint: debt ≤ max satisfying avg(DSCR) ≥ avg_dscr

The binding constraint determines the final debt amount.

3.5 Repayment Schedule Shapes

Five debt schedule shapes are supported (in debt/schedule.py):

  1. equal_principal: Fixed principal each year in repayment period
  2. equal_installment: EMI (level annuity)
  3. dscr_sculpted: Principal sculpted so DSCR = avg_dscr each year
  4. balloon: Interest-only then principal at end
  5. custom_pct_vector: Caller supplies repayment % per year

3.6 Tariff Solver

The solver (solver/tariff.py) uses Brent's method (scipy.optimize.brentq) to find the tariff that achieves target equity IRR:

  • Bracket: [2.0, 8.0] INR/kWh
  • Convergence tolerance: 1e-4
  • Max iterations: 50

3.7 Generation Models

Solar (generation/solar.py):

  • Input: irradiance × capacity_dc → DC power → DC losses
  • Inverter efficiency → AC pre-clip
  • Clipping at MW_AC (DC/AC ratio > 1)
  • Availability × soiling × degradation
  • Output: 25 years × 8760 hours = 219,000 rows

Model chain:

irradiance → DC power → DC losses → inverter → AC losses
→ clipping at MW_AC → availability → soiling → degradation

Wind (generation/wind.py):

  • Wind speed at reference → hub-height correction (power law shear)
  • Power curve lookup → normalized power (0-1)
  • Wake losses × electrical losses × availability × degradation

BESS (generation/bess_state.py):

  • Degradation: SOH = max(eol_soh, 1 - cum_cycles/design_cycles × (1 - eol_soh))
  • Usable MWh = (nameplate + augmentation) × SOH
  • Augmentation steps add capacity at specified years

3.8 Hybrid RTC Dispatch

The dispatch module (dispatch/hybrid_rtc.py) implements hourly charge/discharge:

For each hour h:
  gen = solar[h] + wind[h]
  surplus = gen - target (positive = excess, negative = deficit)
  
  If surplus ≥ 0:
    - Charge BESS with min(surplus, bess_mw, headroom)
    - Curtail excess
  Else:
    - Discharge BESS with min(deficit, available)
    - Shortfall = deficit - discharge

3.9 CLI Commands

# Simulate 25-year solar + wind generation
remodel simulate-gen --input scenario.json --output gen.parquet

# Compute IDC (Interest During Construction)
remodel compute-idc --input capex.json --output idc.json

# Run full scenario pipeline
remodel solve-tariff --input scenario.json --output result.json

4. Packages/API Analysis

4.1 Module Structure

packages/api/src/remodel_api/
├── __init__.py
├── main.py              # FastAPI app, CORS, lifespan
├── config.py           # Settings (environment config)
├── db/
│   ├── __init__.py
│   ├── session.py     # SQLAlchemy async session
│   └── models.py     # Scenario ORM model
├── routers/
│   ├── __init__.py
│   ├── scenarios.py  # CRUD + run + results + SSE + Excel export
│   └── templates.py  # Scenario templates
└── workers/
    ├── __init__.py
    ├── main.py       # Arq worker setup
    └── tasks.py    # Background scenario execution

4.2 API Endpoints

Method Endpoint Description
POST /api/scenarios Create scenario, queue for execution
GET /api/scenarios List scenarios
GET /api/scenarios/{id} Get scenario details
PATCH /api/scenarios/{id}/inputs Update inputs, re-queue
DELETE /api/scenarios/{id} Archive scenario
GET /api/scenarios/{id}/kpis Get KPI results
GET /api/scenarios/{id}/statements Get P&L, CFS, BS
GET /api/scenarios/{id}/export/excel Export .xlsx
GET /api/scenarios/{id}/events SSE progress events

4.3 Database Schema

class Scenario(Base):
    id: str (UUID, primary key)
    name: str
    status: str ("queued", "running", "success", "failed")
    inputs_json: Text (JSON string of ScenarioInput)
    kpis_json: Text (JSON string of KpiSummary)
    statements_json: Text (JSON string of pnl/cfs/bs)
    debt_schedule_json: Text
    timeseries_path: str
    error_message: str
    runtime_s: float
    created_at: datetime
    archived_at: datetime | None

4.4 Background Processing

  • Uses Arq (async Redis-backed task queue)
  • ThreadPoolExecutor runs CPU-bound engine in separate thread
  • Progress published via Redis pub/sub
  • SSE endpoint polls progress

5. Packages/WEB Analysis

5.1 Module Structure

packages/web/
├── app/
│   ├── page.tsx              # Scenario list + wizard
│   ├── layout.tsx            # Root layout
│   ├── providers.tsx         # React Query, etc.
│   ├── globals.css           # Tailwind
│   ├── scenarios/
│   │   └── [id]/
│   │       └── page.tsx      # Scenario detail view
│   ├── compare/
│   │   └── page.tsx          # Scenario comparison
│   └── api-types/           # Auto-generated OpenAPI types
├── components/
│   ├── ui/                  # shadcn/ui components
│   ├── DataGrid/           # AG Grid wrapper
│   ├── ScenarioWizard/       # Input wizard form
│   ├── Charts/              # Recharts visualizations
│   └── KpiCard/            # KPI display card
└── lib/
    └── api.ts              # TypeScript API client

5.2 Frontend Tech Stack

  • Next.js 14 App Router
  • TypeScript (strict mode)
  • shadcn/ui + Tailwind CSS
  • TanStack Query (React Query)
  • AG Grid Community (DataGrid)
  • Recharts (KPIs)
  • Zustand (lightweight state)

6. Domain Context (Indian RE Bidding)

6.1 Key Concepts

  • PPA: Power Purchase Agreement at tariff (₹/kWh)
  • RTC CUF: Round-the-clock capacity factor developer commits to
  • DSM: Deviation Settlement Mechanism penalties
  • IDC: Interest During Construction
  • 115BAA: Indian tax regime (22% + cess = 25.17%)
  • DSCR: Debt Service Coverage Ratio
  • D:E: Debt-to-Equity ratio (typically 75:25)

6.2 Currency

  • Crore (Cr) = 10 million INR (1 Cr = 1,00,00,000)
  • Lakh = 100 thousand INR
  • Capex quoted in Cr/MW or INR/Wp

7. Sprint Status

Sprint Goal Status
S0 Repo setup, CI, API/Web skeleton Complete
S1 Solar + Wind + BESS generation Complete
S2 Capex + IDC calculation In Progress
S3 3-statement financial model Pending
S4 Debt sizing + scheduling Pending
S5 IRR/tariff solver Pending
S6 Full scenario runner Pending
S7 Excel parity gate Pending
S8 Sensitivity sweeps Pending

8. Technical Constraints & Decisions

8.1 Working Agreements (from PROJECT.md)

  1. Engine is UI-agnostic (pip-installable package)
  2. CostItem table model (not flat fields)
  3. Three nested iterations: tariff → debt → IDC
  4. IDC has independent equity/debt drawdowns
  5. Two DSCR compliance knobs
  6. Sync-async hybrid: all runs through Arq queue
  7. SQLite v0, Parquet for timeseries
  8. Excel parity is sacred — must match user Excel within 0.1%
  9. Coverage ≥85%
  10. mypy strict mode
  11. One DataGrid component (shared across 5+ places)

8.2 Testing

  • Unit tests for every public function
  • Integration tests for modules
  • Parity gate — tests against user's Excel gold scenarios
  • Location: packages/engine/tests/
  • Fixtures: packages/engine/tests/fixtures/

9. Observations & Potential Issues

9.1 Strong Points

  1. Clean architecture — engine/API/web separation well-enforced
  2. Pydantic schemas — single source of truth for types
  3. Comprehensive financial model — 3-statement + depreciation + tax
  4. Multiple debt schedule shapes — flexible repayment
  5. Production-ready — Ruff, mypy, pytest, coverage
  6. Async backend — Redis queue for scaling
  7. TypeScript types — auto-generated from OpenAPI

9.2 Potential Concerns

  1. IDC fixed-point — may need more robust convergence handling
  2. Parity gate — not yet validated against user Excel
  3. Multi-user — SQLite v0, needs Postgres for v2
  4. Test coverage gaps — some modules newly added
  5. Wind power curve — generic, may need calibration
  6. Solar profiles — only 3 locations (RJ, KA, GJ)

9.3 Missing/Incomplete (from git status)

The git status shows many new untracked files:

  • packages/engine/src/remodel_engine/capex/ (existing, modified)
  • New modules for dispatch, commercial, debt, financial, irr, solver, scenarios, io
  • packages/web/app/compare/ (new page)
  • Various test updates

10. Recommendations for Discussion

  1. Validation Priority: Run the Excel parity gate with user-supplied gold scenario to verify model accuracy before proceeding to next sprints

  2. Test Coverage: Some newly-added modules (dispatch, commercial, irr) have limited test coverage — prioritize before shipping

  3. DataGrid Usage: Single AG Grid component exists but needs verification across all 5+ use cases

  4. Database Migration: SQLite works for v0, but PostgreSQL planning would help architecture decisions

  5. Wind Profile Calibration: Generic wind power curve may need location-specific calibration for Indian sites

  6. Performance: 30-second target may be achievable, but needs benchmarking with realistic scenarios


11. File Locations Reference

Key Source Files

Component Path
Scenario input schema packages/engine/src/remodel_engine/schemas/scenario.py
Generation simulation packages/engine/src/remodel_engine/generation/solar.py
Wind simulation packages/engine/src/remodel_engine/generation/wind.py
BESS model packages/engine/src/remodel_engine/generation/bess_state.py
RTC dispatch packages/engine/src/remodel_engine/dispatch/hybrid_rtc.py
Capex calculation packages/engine/src/remodel_engine/capex/cost_items.py
IDC calculation packages/engine/src/remodel_engine/capex/idc.py
P&L packages/engine/src/remodel_engine/financial/pnl.py
CFS packages/engine/src/remodel_engine/financial/cfs.py
Balance Sheet packages/engine/src/remodel_engine/financial/bs.py
Depreciation packages/engine/src/remodel_engine/financial/depreciation.py
Tax packages/engine/src/remodel_engine/financial/tax.py
Debt sizing packages/engine/src/remodel_engine/debt/sizing.py
Debt schedule packages/engine/src/remodel_engine/debt/schedule.py
IRR metrics packages/engine/src/remodel_engine/irr/metrics.py
Tariff solver packages/engine/src/remodel_engine/solver/tariff.py
Scenario runner packages/engine/src/remodel_engine/scenarios/runner.py
CLI packages/engine/src/remodel_engine/cli.py
API main packages/api/src/remodel_api/main.py
Scenario endpoints packages/api/src/remodel_api/routers/scenarios.py
Background tasks packages/api/src/remodel_api/workers/tasks.py
Web API client packages/web/lib/api.ts
Main page packages/web/app/page.tsx

End of investigation report.