pnpm workspace monorepo using TypeScript. Each package manages its own dependencies.
- Monorepo tool: pnpm workspaces
- Node.js version: 24
- Package manager: pnpm
- TypeScript version: 5.9
- API framework: Express 5
- Database: PostgreSQL + Drizzle ORM
- Validation: Zod (
zod/v4),drizzle-zod - API codegen: Orval (from OpenAPI spec)
- Build: esbuild (CJS bundle)
artifacts-monorepo/
├── artifacts/ # Deployable applications
│ ├── api-server/ # Express API server
│ ├── power-blockchain/ # MeterChain main web app (React + Vite)
│ └── meterchain-pitch/ # MeterChain pitch deck (14 slides, slides artifact)
├── lib/ # Shared libraries
│ ├── api-spec/ # OpenAPI spec + Orval codegen config
│ ├── api-client-react/ # Generated React Query hooks
│ ├── api-zod/ # Generated Zod schemas from OpenAPI
│ └── db/ # Drizzle ORM schema + DB connection
├── scripts/ # Utility scripts (single workspace package)
│ └── src/ # Individual .ts scripts, run via `pnpm --filter @workspace/scripts run <script>`
├── pnpm-workspace.yaml # pnpm workspace (artifacts/*, lib/*, lib/integrations/*, scripts)
├── tsconfig.base.json # Shared TS options (composite, bundler resolution, es2022)
├── tsconfig.json # Root TS project references
└── package.json # Root package with hoisted devDeps
Every package extends tsconfig.base.json which sets composite: true. The root tsconfig.json lists all packages as project references. This means:
- Always typecheck from the root — run
pnpm run typecheck(which runstsc --build --emitDeclarationOnly). This builds the full dependency graph so that cross-package imports resolve correctly. Runningtscinside a single package will fail if its dependencies haven't been built yet. emitDeclarationOnly— we only emit.d.tsfiles during typecheck; actual JS bundling is handled by esbuild/tsx/vite...etc, nottsc.- Project references — when package A depends on package B, A's
tsconfig.jsonmust list B in itsreferencesarray.tsc --builduses this to determine build order and skip up-to-date packages.
pnpm run build— runstypecheckfirst, then recursively runsbuildin all packages that define itpnpm run typecheck— runstsc --build --emitDeclarationOnlyusing project references
Express 5 API server. Routes live in src/routes/ and use @workspace/api-zod for request and response validation and @workspace/db for persistence.
- Entry:
src/index.ts— readsPORT, starts Express - App setup:
src/app.ts— mounts CORS, JSON/urlencoded parsing, routes at/api - Routes:
src/routes/index.tsmounts sub-routers;src/routes/health.tsexposesGET /health(full path:/api/health) - Depends on:
@workspace/db,@workspace/api-zod pnpm --filter @workspace/api-server run dev— run the dev serverpnpm --filter @workspace/api-server run build— production esbuild bundle (dist/index.cjs)- Build bundles an allowlist of deps (express, cors, pg, drizzle-orm, zod, etc.) and externalizes the rest
Database layer using Drizzle ORM with PostgreSQL. Exports a Drizzle client instance and schema models.
src/index.ts— creates aPool+ Drizzle instance, exports schemasrc/schema/index.ts— barrel re-export of all modelssrc/schema/<modelname>.ts— table definitions withdrizzle-zodinsert schemas (no models definitions exist right now)drizzle.config.ts— Drizzle Kit config (requiresDATABASE_URL, automatically provided by Replit)- Exports:
.(pool, db, schema),./schema(schema only)
Production migrations are handled by Replit when publishing. In development, we just use pnpm --filter @workspace/db run push, and we fallback to pnpm --filter @workspace/db run push-force.
Owns the OpenAPI 3.1 spec (openapi.yaml) and the Orval config (orval.config.ts). Running codegen produces output into two sibling packages:
lib/api-client-react/src/generated/— React Query hooks + fetch clientlib/api-zod/src/generated/— Zod schemas
Run codegen: pnpm --filter @workspace/api-spec run codegen
Generated Zod schemas from the OpenAPI spec (e.g. HealthCheckResponse). Used by api-server for response validation.
Generated React Query hooks and fetch client from the OpenAPI spec (e.g. useHealthCheck, healthCheck).
Utility scripts package. Each script is a .ts file in src/ with a corresponding npm script in package.json. Run scripts via pnpm --filter @workspace/scripts run <script>. Scripts can import any workspace package (e.g., @workspace/db) by adding it as a dependency in scripts/package.json.
The platform implements 6 Hyperledger Fabric channels for the MEITY National Blockchain Framework:
- Channel 1: Smart Meter / Fraud Detection — Dashboard, alerts, theft detection
- Channel 2: Subsidy DBT — Soul-bound subsidy tokens, Aadhaar-linked beneficiary registry, settlement ledger (
/subsidy) - Channel 3: PPA Settlement — Smart contract-automated PPA settlements with escrow enforcement (
/ppa) - Channel 4: P2P Trading — Rooftop solar peer-to-peer marketplace (
/p2p) - Channel 5: REC Lifecycle — Renewable Energy Certificate registry with RPO compliance dashboard (
/rec) - Channel 6: Demand Response — Parametric DR with SLDC grid events, industrial consumer contracts, and auto-settlements (
/demand-response)
lib/db/src/schema/smartMeters.ts— Smart meters and meter readingslib/db/src/schema/transactions.ts— Energy transactions, theft alerts, P2P tradeslib/db/src/schema/subsidy.ts— Subsidy tokens and settlements (Channel 2)lib/db/src/schema/ppa.ts— PPA contracts and settlements (Channel 3)lib/db/src/schema/rec.ts— Renewable energy certs and RPO obligations (Channel 5)lib/db/src/schema/demandResponse.ts— DR contracts, grid events, DR settlements (Channel 6)
artifacts/api-server/src/routes/dashboard.ts— Cross-channel KPI summary + live activity feed API (/api/dashboard/summary,/api/dashboard/activity)artifacts/power-blockchain/src/hooks/use-dashboard.ts— React Query hooks for dashboard endpointsartifacts/power-blockchain/src/pages/dashboard.tsx— Upgraded command center dashboard with Platform Impact cards, Live Activity Feed, Channel Health, and existing CH-1 stats/chart
seed-power— Core smart meter, transaction, and alert dataseed-subsidy— Subsidy tokens and settlement history for 10 beneficiaries across 5 statesseed-ppa— 7 PPA contracts (NTPC Dadri, Adani Solar, ReNew Wind, Tata Power, KSEB Hydro, NLC Neyveli, Suzlon Wind) with 24 settlementsseed-rec— 14 RECs from solar/wind farms across RJ/GJ/TN/KA/MH, plus 8 DISCOM RPO obligationsseed-dr— 6 DR contracts (data centres, steel plant, cold chain, automobile, refinery), 4 grid events, 6 settlementsseed-governance— 6 governance proposals (CERC/SERC/MEITY/FOR/MoP/POSOCO) across all 4 proposal types, 13 votes
lib/db/src/schema/governance.ts—governance_proposalsandgovernance_votestablesartifacts/api-server/src/routes/governance.ts— GET /governance (combined {proposals, summary}), GET /governance/:id ({proposal, votes})artifacts/power-blockchain/src/hooks/use-governance.ts— React Query hooks for governance endpointsartifacts/power-blockchain/src/pages/governance.tsx— Governance & Regulatory Proposals page with list/detail views, vote ledger, and vote progress bars
lib/db/src/schema/greenCerts.ts—green_certificatestable (holder name/type, coverage period, green kWh, linked REC count/IDs, P2P kWh, CO₂ offset, SHA-256 cert hash, tx hash, status active/expired/revoked)artifacts/api-server/src/routes/green-certs.ts— GET /api/green-certs (list + summary), GET /api/green-certs/summary (detailed summary with holder-type breakdown), GET /api/green-certs/:id (detail with linkedRecIdsList)artifacts/power-blockchain/src/hooks/use-green-certs.ts— React Query hooks for green cert endpointsartifacts/power-blockchain/src/pages/green-certs.tsx— Green Provenance Certificates page with summary banner, registry table, detail drill-down, and "Verify on Chain" buttons for linked RECsseed-green-certs— 5 green provenance certificates: Infosys Mysore, Wipro Hinjewadi, Whitefield Greens Housing Society, CtrlS Data Centre, JSW Steel Industrial Unit
artifacts/api-server/src/routes/insights.ts— GET /api/analytics/insights: hourly consumption (24-bucket purely from energy_transactions), grid stress windows derived from grid_events, tier benchmarks (percentiles from subsidy settlements), DR enrolled + potential consumer summary (potential derived from energy transaction volumes via smart_meters join, >=5kW threshold)artifacts/api-server/src/routes/dr-nudges.ts— GET /api/analytics/dr-nudges: top-5 DR candidates ranked by unrealised annual earning potential, mixing enrolled contracts and non-enrolled consumers (joined via smartMetersTable.consumerId to exclude already-enrolled)artifacts/power-blockchain/src/hooks/use-insights.ts— React Query hooks for insights + DR nudges endpointsartifacts/power-blockchain/src/pages/insights.tsx— Energy Insights & DR Nudges page with 4 stat cards, 24-hour Recharts BarChart with ReferenceArea stress window bands + bar color coding, peer benchmark range bars by subsidy tier, enrolled DR contract cards, potential DR candidate cards, and enrolled-vs-potential nudge rankings
artifacts/api-server/src/routes/verify.ts— Read-only verification endpoints for external GovTech consumersGET /api/verify— Service catalogue listing all 5 verification endpoints with example IDsGET /api/verify/meter/:meterId— Smart meter on-chain verification with tamper statusGET /api/verify/rec/:recId— REC lifecycle verification (retired RECs return verified:false)GET /api/verify/dr/:eventId— DR grid event verification with settlement aggregatesGET /api/verify/subsidy/:tokenId— Subsidy token verification with disbursement totalsGET /api/verify/ppa/:contractId— PPA contract verification with escrow balance
- Uniform response shape:
{ verified, recordId, channel, chaincode, txHash, verifiedAt, summary } - Not-found/retired records return
{ verified: false, reason: "..." }