A dead-simple, self-hosted web app for mapping and documenting your electrical breaker panel. Open it with a QR code. Never wonder again.
Got new garage lights? Need to know what's behind breaker B8? Panel Notes is the answer. It grew out of this Home Assistant issue after realizing a handwritten directory on the panel door wasn't cutting it anymore.
The goal is simple:
- 👀 See the whole panel at a glance (odd on the left, even on the right)
- 📝 Double-click any breaker to see its label, notes, and linked devices
- 📱 Open the app instantly from a QR code taped to the panel
- 🔧 40-slot GE panel layout (1A/1B | 2A/2B style) — but easy to adapt to your setup
- 📱 Mobile-first UI — both sides of the panel stay visible on phones
- ✏️ Modal editor — breaker label + notes + linked devices, all in one place
- 📄 CSV-backed data — edit or back it up with any text editor
- 🔌 Simple REST API — ready for future integrations (Home Assistant, anyone?)
| Layer | Technology |
|---|---|
| Frontend | React + Vite (modern, component-based, mobile-first) |
| Backend | Express (Node.js) — serves API and static build |
| Data | Flat CSV files (breakers.csv, devices.csv) |
| Deployment | Docker with multi-stage build |
# Clone the repo
git clone https://github.com/yourusername/panel-notes.git
cd panel-notes
# Install dependencies
npm install
# Start dev mode (Vite + API)
npm run dev
# Open:
# UI: http://localhost:5173
# API: http://localhost:8080# In the repo root
docker compose up --build -d
# Open http://localhost:8080Data persists via bind mount (./data:/app/data). Change the port by setting PORT in .env.
cp .env.example .envEnvironment Variables:
PORT– API/web port inside container (default:8080)DATA_DIR– CSV storage path inside container (default:/app/data)
Simple endpoints, ready for integrations:
GET /api/health # Health check
GET /api/breakers # List all breakers
GET /api/breaker/{id} # Get breaker details
PUT /api/breaker/{id} # Update breaker
GET /api/devices # List all devices
POST /api/device # Create device
GET /api/device/{id} # Get device details
PUT /api/device/{id} # Update device
GET /api/search?q=garage # Search breakers/devices
GET /api/map/light-to-breaker # Device-to-breaker mapping
{
id: "A1", # Internal ID
side: "A", # A or B
row: 1, # Row 1–20
label: "Garage Lights",# Human-friendly
load_type: "Lighting", # Optional type
notes: "...", # Free-form
tags: "garage,lights" # Comma-separated
}
{
id: "D1",
name: "Garage Light 1",
type: "Light",
notes: "Main fixture",
linked_breakers: "A1,A2"
}
Here's the dream setup:
- Deploy Panel Notes on a Docker host on your LAN
- Generate a QR code pointing to the Panel Notes URL (e.g.,
http://panel-notes.local:8080) - Print & Tape the QR inside your panel door
- Scan when working at the panel — instant access to the live map
Works in any house, lab, or workshop. 🔌
We'd love your help! Check CONTRIBUTING.md for ideas and guidelines.
Ideas we'd love:
- Layout customization for other panel types
- Home Assistant integration examples
- Mobile app wrapper
- Cloud sync option (optional)
MIT – see LICENSE for details.


