EIS v2: Python/React Dashboard Rebuild (Local First)
python-reactfullstack-rebuildlocal-first
# EIS v2 — Python + React Rebuild (Local First) ## Your role You are a senior full-stack engineer rebuilding the **EIS (Env IoT Solutions)** dashboard from a legacy **Ruby on Rails 6** app into **Python backend + React frontend**. Work incrementally, test each phase, and keep the legacy Rails app as read-only reference only — do not extend Rails. ## Workspace layout (expected on my Mac) - `eiotsolutions-rails-reference/eiotsolutions/` — extracted Rails reference (from AWS backup) - `eiotsolutions-rails-reference/eis-db-backup.sql` — MySQL dump (sensitive — never commit) - `eis-v2/backend/` — NEW Python API (create this) - `eis-v2/frontend/` — NEW React app (create this) If paths differ, ask me once, then proceed. --- ## Why we are rebuilding Rails + ERB + jQuery + SlimSelect is hard to maintain. We want: - Clean React UI (MUI or React Select for dropdowns — no SlimSelect) - Python API with clear service layer - Celery + Redis for background jobs (PDF, email, EIS data fetch) - Same business behavior as production (NFPA LS compliance is critical) --- ## Target tech stack (use this unless blocked) ### Backend - **Python 3.11+** - **Django 5 + Django REST Framework** (preferred — similar to Rails monolith patterns) - **PostgreSQL** for new app DB (import/migrate from MySQL dump OR use MySQL initially if Postgres migration is too slow — document choice) - **Celery + Redis** for async jobs - **python-dotenv** for secrets - **WeasyPrint** or **ReportLab** for NFPA PDFs (port layout from Rails `NfpaReportPdfJob` — match output, not necessarily same library) ### Frontend - **React 18 + TypeScript + Vite** - **MUI (Material UI)** for layout, tables, forms, selects - **React Router** for navigation - **TanStack Query (react-query)** for API caching - **Axios** for HTTP ### Auth - JWT or session-based API auth replacing Devise - Roles: `sa` (admin), `vr` (viewer), `pu` (pick up from Rails `users.role`) - Building access via `user_buildings` table logic --- ## Legacy reference — read these first before coding ### Schema & data - `eiotsolutions-rails-reference/eiotsolutions/db/schema.rb` — all tables - Key tables: `users`, `user_buildings`, `sites`, `buildings`, `floors`, `sensors`, `readings`, `life_safety_details`, `ls_reports`, `aq_reports`, `alerts`, `aqi_settings`, `life_safety_settings`, `nfpa_report_exports`, `smtp_configs` ### Business logic (PORT WITH TESTS — highest risk) - `app/services/ls_test_result_mapper.rb` — NDL, NNT, Passed, Failed, compliant labels - `app/services/life_safety/` — annual/monthly queries, compliance evaluator, monthly compliance - `app/jobs/nfpa_report_pdf_job.rb` — NFPA PDF structure (monthly grid + annual summary + detail) - `lib/tasks/fetch_eis_data.rake` — EIS API ingestion (Keycloak token + prod-api-eis.ilumisolutions.net) - `lib/tasks/high_aqi_common_ls.rake` — LS/AQ report aggregation, monthly/yearly LsReport creation - `lib/setup_cron.rb` — schedules (15 min fetch, etc.) ### UI reference (behavior, not copy-paste ERB) - `app/views/home/_header.html.erb` — nav: AQ, LS, Events, Reports, Alerts, Admin - `app/views/home/dashboard.html.erb`, `aqi_view.html.erb`, `life_safety_view.html.erb` - `app/views/home/report_data.html.erb` — reports + NFPA PDF export - `app/views/home/settings.html.erb` — alerts settings pattern (mirror for future report settings) - `app/controllers/home_controller.rb` — main routes/actions ### External APIs (from rake tasks) - Token: `https://identity.ilumisolutions.net/realms/meshtek-eis/protocol/openid-connect/token` - API base: `https://prod-api-eis.ilumisolutions.net/api` - Endpoints: `eisreadings?type=QUALITY`, `eislsdetail?type=LSD`, etc. - Credentials come from `.env` — do NOT hardcode; ask me to fill `.env.example` --- ## Database setup (local) 1. Import `eis-db-backup.sql` into local MySQL OR migrate to Postgres 2. Document connection in `eis-v2/backend/.env.example` 3. Phase 1: Django models can mirror existing table names to avoid data migration pain 4. Never commit SQL dumps or production passwords Production DB name was `eis_prod_2026`. Local name: `eis_dev`. --- ## Implementation phases — follow in order ### PHASE 0 — Project scaffold (Day 1) - Create monorepo `eis-v2/` with `backend/` and `frontend/` - Backend: Django project `config`, apps: `core`, `accounts`, `buildings`, `life_safety`, `air_quality`, `reports` - Frontend: Vite React TS, MUI theme (purple accent `#662f92` like current EIS branding) - CORS enabled for `http://localhost:5173` - `.gitignore`: `*.sql`, `.env`, `node_modules`, `__pycache__`, `.venv` - README with how to run backend, frontend, celery, redis locally Deliverable: empty app runs; health check `GET /api/health` returns OK. --- ### PHASE 1 — Auth + navigation shell (Week 1) **Backend** - Port `users` + `user_buildings` access control - Login endpoint returning JWT (or session cookie) - `GET /api/me` — current user + role + allowed sites/buildings **Frontend** - Login page - App shell matching EIS header: AQ | LS | Events | Reports | Alerts | Admin - Site + Building multi-select filters (MUI Autocomplete or React Select — must work reliably) - Stats bar: BUILDINGS, SITES, DEVICES counts (from API) - Protected routes; redirect to login if unauthenticated Deliverable: login as existing user from DB; pick site/building; header renders. --- ### PHASE 2 — AQ dashboard (Week 2) **Backend** - `GET /api/aq/dashboard?building_id=` — latest readings per sensor, 24H high, 30D high - Port gauge band logic from Rails JS/docs if needed (segments, cap at 500) **Frontend** - AQ dashboard page: semi-circular gauge (Chart.js or MUI-compatible chart) - Sensor table: IAQ, CO, CO2, NOx, PM*, RHM, TMP, VOC columns - Match columns from `aqi_view` / dashboard Deliverable: AQ page matches Rails data for one test building (e.g. Hasco). --- ### PHASE 3 — LS dashboard (Week 2–3) **Backend** - `GET /api/ls/dashboard?building_id=` — unit status counts, LS type counts, current month testing stats - `GET /api/ls/sensors/:sensor_id/detail` — LS detail view data **Frontend** - LS summary page like `life_safety_view` - LS detail page like `ls_detailed_view` Deliverable: LS dashboard + detail for one building. --- ### PHASE 4 — Reports (Week 3–4) **Backend** - `GET /api/reports/ls?building_id=&type=monthly|annual&month=&year=` - `GET /api/reports/aq?...` (read from `aq_reports`) - CSV export endpoints **Frontend** - Reports page like `report_data.html.erb` - Filters: report type, month/year, pagination - Download CSV button Deliverable: reports table matches Rails for same filters. --- ### PHASE 5 — NFPA PDF export (Week 4–6) — CRITICAL **Backend** - Port `LsTestResultMapper` to Python with unit tests (copy cases from Rails behavior) - Port `LifeSafety::MonthlyCompliance`, `AnnualSummaryQuery`, `AnnualDetailQuery` logic - Celery task `generate_nfpa_pdf(export_id)` mirroring `NfpaReportPdfJob` - Store PDFs in `backend/media/reports/` or `public/reports/` - API: `POST /api/reports/nfpa/export`, poll status, download **Known business rules to implement (from client RCAs)** - Annual report: exclude sensors where `created_at > end_of_report_year` (e.g. TB5 must not appear in 2025 report) - Annual new-unit waiver (when approved): units installed in report year with no annual test but passing monthly → Compliant YES + provision date in Comments - Monthly: grace period `provisioned_at + 1 month + 7 days` **Frontend** - "Download NFPA report" button with async polling modal (like current UX) Deliverable: PDF for Hasco CT Office monthly/annual matches Rails output closely; unit tests green. --- ### PHASE 6 — Alerts (Week 5–6) - Alert list pages: AQ alerts, LS alerts, sensor alerts - Alert settings page pattern from Rails `settings.html.erb` (internal user picker from `user_buildings`) --- ### PHASE 7 — Background jobs (Week 6+) - Celery task port of `fetch_eis_data.rake` (every 15 min — use Celery Beat) - Port `high_aqi_common_ls.rake` aggregation for `ls_reports` / `aq_reports` - Use env vars for EIS API credentials --- ### PHASE 8 — LS Report Settings + Archive + Auto-email (from client mockups) **Only after Phase 5 PDF works** **Settings** - Reports nav dropdown: Report Settings | LS Report Archive - LS Report Settings per building: - Internal Auto Send toggle + Monthly/Annual notify types - External Auto Send toggle + Monthly/Annual notify types - Add External modal: Name, Title, Email (stored per **site**, no dashboard login) - Internal recipients = all users with `user_buildings` access to that building **Archive** - Page listing `nfpa_report_exports` (ready PDFs), filter site/building/report type, 7-year history - Checkbox multi-select + Download Selected (zip) **Scheduled jobs** - Monthly: 2nd of month 1:00 AM UTC — previous month PDF per eligible building - Annual: Jan 2 1:00 AM UTC — previous year PDF - Email PDF as attachment via SMTP (`smtp_configs` table port) --- ## Coding standards - Minimize scope per PR/commit; one phase at a time - Python: type hints, services in `services/` not fat views - React: functional components, hooks, no jQuery - Write tests for compliance logic (pytest) - Match existing API field names where possible for easier frontend mapping - Comments only for non-obvious NFPA business rules ## Do NOT - Do not modify Rails reference code except to read it - Do not commit SQL dumps, `.env`, or SMTP passwords - Do not use SlimSelect - Do not big-bang rewrite everything in one pass - Do not change NFPA compliance rules without citing Rails reference behavior ## Environment variables (.env.example)
0 likes0 comments
Want to like, comment or save this prompt?
Sign up free to interact, create and organise your own AI prompts.
Get Started Free