- JavaScript 99.8%
| backend | ||
| docs | ||
| Specs | ||
| src | ||
| .dockerignore | ||
| .env.example | ||
| docker-compose.full.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| index.html | ||
| package.json | ||
| postcss.config.js | ||
| README.md | ||
| tailwind.config.js | ||
| vite.config.js | ||
Ameren MO Rate Plan & Battery Storage Calculator
Interactive web app for comparing Ameren Missouri residential rate plans, modeling battery/solar ROI, evaluating backup runtime, and reconciling modeled bills against actual Ameren bills.
Run Frontend Only
docker compose up --build
Then open http://localhost:3000.
Run Full Stack
cp .env.example .env
docker compose -f docker-compose.full.yml up --build
The full stack starts:
- frontend on port
3000 - backend API on port
4000 - PostgreSQL with a persistent Docker volume
Homelab / Caddy
The app works behind a normal subdomain reverse proxy. Point Caddy at the frontend container if you only run the frontend, or at the backend/frontend ports separately if you split them.
One simple pattern is:
battery.example.com {
reverse_proxy 10.1.1.14:3000
}
If you expose backend APIs through the same hostname, proxy /api/* and /auth/* to the backend and everything else to the frontend:
battery.example.com {
handle /api/* {
reverse_proxy 10.1.1.14:4000
}
handle /auth/* {
reverse_proxy 10.1.1.14:4000
}
handle {
reverse_proxy 10.1.1.14:3000
}
}
Authentik / OIDC
Authentication is configured with environment variables. No Authentik groups are required; home roles are managed inside the app.
Required for OIDC mode:
AUTH_MODE=oidcAUTH_REQUIRED=truePUBLIC_APP_URL=https://battery.example.comSESSION_SECRET=<long random value>OIDC_ISSUER_URL=<Authentik issuer URL>OIDC_CLIENT_ID=<client id>OIDC_CLIENT_SECRET=<client secret>OIDC_REDIRECT_URI=https://battery.example.com/auth/callback
The backend validates OIDC issuer, audience, expiration, signature, and login nonce. API routes for home-scoped data require home membership once auth is enabled.
Data Sources
- Emporia usage: CSV import is the active path. Backend sync jobs and integration settings exist for a future official or user-provided adapter.
- Weather: CSV import or Open-Meteo historical daily temperature sync using the home latitude/longitude.
- Ameren billing: manual entry or CSV import. Ameren Missouri customer billing API support is not assumed.
Configuration And Backups
- Browser state persists in localStorage.
- JSON export/import remains available in the My Data tab.
- Backend snapshot migration is available in the My Data tab when the API is reachable.
- PostgreSQL backup example:
docker compose -f docker-compose.full.yml exec postgres pg_dump -U battery battery_storage > battery_storage.sql
Restore example:
docker compose -f docker-compose.full.yml exec -T postgres psql -U battery battery_storage < battery_storage.sql
Features
- Overview: rate comparison, dispatch impact, and rate reference.
- My Data: Emporia CSV import, circuit backup status, outage priority, persistence tools.
- Batteries: configurable battery library and cost metrics.
- Backup: reserve settings, outage scenarios, load shedding, SOC/load charts.
- Weather: home location, geocoding, weather import/sync, temperature correlation.
- Solar: panel library, installer costs, export/no-export settings, lifetime production.
- Billing: manual/CSV bill import and modeled-vs-actual reconciliation.
- Quotes: installer quote scenarios with included hardware and revision history.
- Projections: 15-year savings and payback projections.
- Admin: auth status, homes, memberships, integration status, and backend diagnostics.
Development
Frontend tests:
npm test
Backend tests:
npm --prefix backend test
Production build:
npm run build