📚 Documentation

Engineer-grade docs.

The model behind the engine, the rule packs that drive verdicts, the API surface for automation, and the runbook for operating EEP. Written for engineers and DevOps — no marketing fluff.

Quickstart

From zero to a sealed PDF in under 10 minutes.

1. Sign up

Create an account at /login. The first project is free under the residential ≤ 300 m² rule. Beyond that, the Pro plan starts a 14-day trial — no card required.

2. Pick a template (optional)

From the workflow page, choose residential-200a, commercial-office, industrial-derate, or evse-retrofit. The template seeds service, panels, and a starter load list.

3. Edit anywhere

Service voltage, panel layout, load list, conduit material — change anything. The verdict bar at the top updates instantly: total demand, calculated service amps, voltage drop, conduit fill, LPD verdict, free-tier status.

4. Resolve warnings

Each warning carries a code (e.g. VD_FEEDER_OVER), a list of affectedElementIds, and a suggested fix. Click through to jump to the offending element.

5. Stamp & export

Move the project from UNDER_REVIEW to STAMPED (requires a P.E. / P.Eng on the team). Export the report PDF + single-line PDF.

Core concepts

Five ideas you need to know before reading any other doc.

ProjectState

A single immutable JSON document describing the entire project: meta, service, panels, loads, feeders, equipment, options. Everything else is derived from it.

derive(state)

A pure function. Same state in → same outputs out. No hidden DB calls, no time-dependent behavior. This is what makes EEP auditable.

Rule pack

A code object (NEC_2023_PACK, CEC_2024_PACK) listing every rule the engine evaluates. Each rule has an ID, a citation, and a function.

Element graph

Every element (panel, load, feeder) has a stable ID. The graph tracks parents and dependents so deletion impact is always knowable.

Snapshot

A (projectId, version) tuple in the database holding the full state at that moment. Versions are immutable; restore creates a new version.

NEC / CEC rule packs

Both packs ship in every plan. Switch per project.

NEC 2023 (US)

Articles 210, 215, 220 (incl. T220.42 occupancy variants for hotel / school / hospital), 230, 240, 250, 310 (T310.16 ampacity, derating for ambient + bundling), 408, 430 (motors), 450 (transformers), 625 (EVSE), Chapter 9 T1 (conduit fill).

CEC 2024 (Canada)

Sections 4 (conductors + T2/T4), 6 (services), 8 (loads + 8-200 calculation, 8-202 multi-dwelling, 8-210 commercial), 10 (grounding), 14 (overcurrent), 26 (transformers), 28 (motors), 86 (EVSE).

Provincial flags

CEC mode applies provincial deviations where they exist (Ontario 26-700 service-disconnect amendments, BC 4-006 conductor fill, Quebec rule numbering). Each fired rule includes a citation.

derive(state) — engine surface

The single function the entire app reads from.

import { derive } from '@eep/engine'
const result = derive(projectState)

result.totalConnectedKva    // raw connected load
result.demandKva            // post-demand-factor
result.calculatedAmps       // service ampacity needed
result.feeders              // [{ id, conduitSize, conduitFillPct, vdPct, ... }]
result.panelSchedule        // [{ panelId, totalConnectedKva, legBalance, ... }]
result.warnings             // [{ code, severity, message, affectedElementIds }]
result.firedRuleIds         // ['NEC-220.84', 'NEC-T220.42-hotel', ...]
result.freeTier             // { eligible: boolean, reason?: string }
result.lpd                  // { pass, allowance, actual, ratio } | null

The function is exposed as a TypeScript module (@eep/engine) and over HTTP at POST /api/v1/engine/derive.

Warning codes

26 codes. Every code carries severity, message, and the element IDs it touches.

CodeSeverityTrigger
VD_BRANCH_OVERerrorBranch voltage drop > configured limit
VD_FEEDER_OVERerrorFeeder voltage drop > configured limit
AMPACITY_INSUFFICIENTerrorConductor ampacity < calculated load after derate
CONDUIT_OVERFILLerrorConduit fill > 40 % (NEC) / 40 % (CEC) for 4+ wires
PANEL_BALANCE_OFFwarn3φ panel leg imbalance > 10 %
FREE_TIER_GATEinfoProject exceeds free-tier eligibility
LPD_OVERwarnLighting power density > ASHRAE / NECB allowance
NEUTRAL_NONLINEARwarn> 50 % non-linear load on 3φ feeder — neutral upsize
ORPHAN_ELEMENTwarnElement references a deleted parent
…and 17 more. See /element-graph/warnings.ts for the full list.

Calc extensions

Targeted modules called from derive() for non-trivial sub-calculations.

conduit-fill.ts

NEC Chapter 9 Table 1. pickConduit(awgList, type) returns trade size + fill %, or flags parallel-runs needed.

lpd.ts

ASHRAE 90.1 / NECB 2017 lighting power density allowances by occupancy. checkLpd(occupancy, m², actualW/m²).

free-tier.ts

Business rule: residential dwellings ≤ 300 m² are free forever; everything else requires a paid plan.

equipment-library.ts

40+ real manufacturer items (Square D, Eaton, Siemens, ABB, Schneider). Filter by manufacturer, kind, amps.

csv-import.ts

CSV / TSV importer with header aliasing and per-row error reporting.

Projects & versions

Optimistic concurrency on (projectId, version). No lost writes, no overwritten teammate edits.

Save

Every save creates a snapshot row. The version column is unique per project; concurrent saves with the same version receive 409 Conflict and must rebase.

Restore

Restoring an older version creates a new version with that content — the older row stays untouched. History is append-only.

Branch

POST /projects/:id/branch?fromVersion=N creates a new project rooted at version N. Use it to explore an alternative without polluting the live design.

Templates

Four built-ins. Point of departure, not point of arrival.

  • residential-200a — single-family, 200 A service, NEC 2023
  • commercial-office — 480/277 V, panel + lighting + receptacle distribution
  • industrial-derate — motor-heavy, ambient + bundling derate scenarios
  • evse-retrofit — adding 1–6 EVSE to existing residential service

Status & sealing

DRAFT → UNDER_REVIEW → STAMPED → ARCHIVED.

The status transition UNDER_REVIEW → STAMPED requires a team member with the SEAL role. The actor's name + license number are written into the audit log permanently. STAMPED versions are content-locked; further edits create a new branch.

Auth

Bearer JWT. Tokens issued at POST /auth/login, refreshed at POST /auth/refresh.

curl -X POST https://api.ee-platform.com/api/v1/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"[email protected]","password":"…"}'

# response: { "accessToken": "eyJ…", "refreshToken": "eyJ…" }

Enterprise plans support SAML / OIDC SSO with custom IdP. Contact [email protected].

REST endpoints (selected)

~25 endpoints total. The most-used are listed here; the rest live behind your dashboard's API explorer.

VerbPathPurpose
POST/projectsCreate project (optionally from template)
GET/projectsList your projects
GET/projects/:idLatest version of a project
POST/projects/:id/snapshotsSave a new version (optimistic on version)
POST/projects/:id/restoreRestore an older version as a new version
POST/projects/:id/branchFork into a new project
PATCH/projects/:id/statusMove DRAFT → UNDER_REVIEW → STAMPED
POST/projects/:id/elements/:eid/force-deleteDelete element with reason + impact log
GET/projects/:id/changes?since=NPoll for teammate edits
GET/projects/:id/auditImmutable audit log
POST/engine/deriveRun derive() on a state without persisting
POST/loads/importCSV / TSV bulk import
GET/equipmentSearch the equipment library
POST/public/contactPublic contact form (no auth)

Webhooks

Pro plan and above. POST your endpoint when events fire.

Configure at /settings/webhooks. Events: project.saved, project.stamped, project.warning_added, project.element_deleted. Payload includes project ID, version, actor email, and a HMAC-SHA256 signature in the X-EEP-Signature header.

Deployment

Hosted SaaS or self-host on Railway + Supabase + Cloudflare Pages. (Enterprise.)

Hosted

Default. Backend on Railway, database on Supabase (Postgres 15), static frontend on Cloudflare Pages. SOC 2 Type I in progress; backups every 6 h, point-in-time recovery to 7 days.

Self-host (Enterprise)

Provided as a Docker Compose bundle: backend (NestJS), Postgres 15, Redis (optional, for Bull queues). Migration: pnpm prisma migrate deploy. See RUNBOOK.md in your customer share.

Runbook (operations)

For DevOps. The bare minimum to keep EEP healthy.

Health

GET /healthz returns 200 ok if the API is up; GET /readyz additionally pings the DB. Wire both into your uptime monitor.

Migrations

Always backwards-compatible inside a single major. Run pnpm prisma migrate deploy on release; never migrate reset against production.

Backups

Hosted: daily logical (pg_dump) + WAL streaming. Self-host: configure your own; do not skip this.

Incident

Status page: status.ee-platform.com. Sev-1 hotline (Enterprise): in your contract.

Security

Light on theatre, heavy on the basics.

  • TLS 1.2+ everywhere; HSTS on the marketing + app domains
  • Argon2id password hashing; 30-min access JWTs, 14-day refresh
  • Rate limit on /auth/* and /public/* via helmet + custom guard
  • Tenant isolation on every Prisma query (global guard)
  • SOC 2 Type I in progress; full report at /security
  • Disclosure: [email protected]