English · 简体中文
Occupancy-driven after-hours energy and carbon management for office buildings.
Office towers cool and light whole floors on fixed schedules. After hours and at weekends the building keeps paying for floors nobody is on, while the few people who stay late often get no cooling at all. FlowCarbon counts people per floor, finds the hours a floor was cooled or lit for nobody, forecasts after-hours headcount, lets tenants book cooling for their own floor instead of the whole tower, and prices the saving under an energy performance contract — with every number traceable to the rule and the data behind it.
Status: 0.2. The engine, data platform, API, worker and web app are implemented and tested end to end. All bundled data is simulated; nothing here describes a real building.
| Sense Door counters give people per floor; BMS states and sub-meters give what runs and what it costs. Every kWh is tagged measured or estimated. |
Detect Four rules with a physical meaning and a written rationale for every threshold. Each interval's energy is counted by at most one rule. |
Explain Claude explains a finding, recommends one action from a fixed strategy list and cites only a closed list of sources. Rules decide; AI explains; people choose. |
| Forecast & simulate After-hours headcount for the next seven days per floor; strategies annualised by day type; EPC split, paybacks and NPV. |
Report Electricity and Scope 2 by the location- and market-based methods, with factor provenance, CSV export and frozen snapshots. |
Operate Multi-tenant with PostgreSQL row-level security, roles with tenant scoping, scoped API keys for gateways, audit log, metrics. |
| Ask Ask for a target or say "turn the lights off at night". Plans and figures come from code over the building's own data; Claude reads the request and writes the words, and a template takes over if it can't. |
Compare & share Strategies side by side, before and after, with their basis and a stated range. Adopting one creates real measures that the data then verifies. Buildings can publish a strategy and reuse each other's. |
Digital twin A simulated floor, open plan or meeting rooms, with lights switched by row or room and fan coils by zone. See what a policy draws and how bright each desk stays. It assumes controls can switch equipment directly. |
Screens from the bundled simulation of “Tower A”; no real building or person is shown.
flowchart LR
subgraph building["Building (simulated)"]
door[Door counters]
bms[BMS / HVAC states]
meter[Sub-meters]
end
door & bms & meter -->|API key · idempotent batches| api
web["Web app · Next.js<br/>English / 中文"] -->|session cookie| api
api["API · Fastify<br/>roles · audit · OpenAPI"] --> db[("PostgreSQL 17 + TimescaleDB<br/>row-level security")]
api -->|jobs| queue[["pg-boss"]]
queue --> worker["Worker<br/>intervals · rules · forecasts"]
worker --> db
worker -->|structured output| claude["Claude<br/>explains, never decides"]
- Rules decide, AI explains. Waste is detected by rules with a physical meaning and a documented rationale for every threshold. The AI explains findings and recommends one action from a fixed strategy list; it never decides and never changes building settings.
- No estimate is shown as a measurement. Every energy figure carries its data tier (
measuredfrom a sub-meter, orestimatedfrom rated power × run time). - Cost first, carbon alongside. Owners act on electricity cost. Scope 2 is reported by both the location-based and the market-based method with factor provenance. It is an energy and carbon report, not an ESG report.
- Multi-tenant from day one. Every organisation's rows are isolated by the database itself, and the runtime role cannot bypass it.
docker compose -f infra/docker-compose.yml --profile app up -d --build
DEMO_PASSWORD='choose-a-password' docker compose -f infra/docker-compose.yml --profile demo run --rm seed
open http://localhost:3000 # sign in as manager@flowcarbon-demo.examplePrebuilt images: ghcr.io/3351666087/flowcarbon-server and ghcr.io/3351666087/flowcarbon-web
(linux/amd64 and linux/arm64). API documentation is served at http://localhost:4000/api/v1/docs.
See deployment for production settings.
| Rule | Kind | What it checks |
|---|---|---|
hvac_unrequested_non_working |
waste | On a weekend or holiday a floor is cooled outside its own request with nobody there, while another floor did request cooling. |
hvac_empty_floor |
waste | Cooling continues after the floor has been empty for the grace period (default 30 min). |
lights_on_empty_night |
waste | Lighting above the security level stays on at night on an empty floor. |
full_floor_few_people |
opportunity | The whole floor is cooled for fewer people than the threshold; a zone setback would serve them. |
Pre-cooling and arrival around the start of the working day are exempt. Thresholds and their rationale live in
packages/core/src/rules.ts.
| Layer | Choice |
|---|---|
| Language | TypeScript (strict), Node.js 22, npm workspaces |
| Data | PostgreSQL 17, TimescaleDB 2.30 (hypertables, compression), Drizzle ORM, row-level security |
| API | Fastify 5, zod, OpenAPI 3.1, argon2id, Prometheus metrics |
| Jobs | pg-boss 12 |
| AI | Claude via the Anthropic SDK (structured output, refusal fallback) |
| Web | Next.js 16, React 19, Tailwind CSS 4, TanStack Query, Recharts |
| Delivery | Docker images, Docker Compose, GitHub Actions CI and release |
| Path | What it is |
|---|---|
packages/core |
Pure domain engine: calendars, door-count occupancy, 15-minute floor intervals, rules, forecasts, strategies and EPC finance, overtime, tariffs, Scope 2, reports. No I/O. |
packages/sim |
Deterministic simulator of a 12-floor tower for development, tests and demos. |
packages/db |
Schema and migrations: hypertables, row-level security, runtime role grants, shared emission-factor library. |
packages/pipeline |
Ingestion, interval recompute, daily roll-ups, detection, forecasts, reports and strategies on the database. |
packages/security |
argon2id password hashing, opaque tokens, API keys. |
packages/jobs |
Job queues: definitions, owner-only schema install, runtime client. |
packages/demo |
Seeds a demonstration organisation through the real ingestion path. |
apps/api |
HTTP API. |
apps/worker |
Background jobs and AI explanations. |
apps/web |
Web application. |
apps/android |
Android app: a native shell around the web app (details). |
docs/ |
Architecture, deployment, decision records. |
Requires Node.js 22 and Docker. Settings are environment variables; see .env.example.
npm install
npm run db:up # PostgreSQL 17 + TimescaleDB on localhost:5432
export DATABASE_URL=postgres://flowcarbon:flowcarbon-dev@localhost:5432/flowcarbon
npm run db:migrate # migrations, shared reference data, job queues
DEMO_PASSWORD='choose-a-password' npm run seed -- --reset # simulated Tower A, last 28 days
DATABASE_URL=postgres://flowcarbon_app:flowcarbon-app-dev@localhost:5432/flowcarbon npm run dev:api
DATABASE_URL=postgres://flowcarbon_app:flowcarbon-app-dev@localhost:5432/flowcarbon npm run dev:worker # ANTHROPIC_API_KEY optional
npm run dev -w @flowcarbon/web # http://localhost:3000
npm test # set TEST_DATABASE_URL to include database and API tests
npm run lintTEST_DATABASE_URL must point at the server as its owner, for example
postgres://flowcarbon:flowcarbon-dev@localhost:5432/postgres. Each run creates and drops its own database and
exercises the pipeline as the non-privileged application role, so row-level security is tested for real.
npm run snapshot -- --out snapshot.json seeds a throw-away database for the README window, runs the whole
pipeline and writes one self-contained JSON file (floors, daily roll-ups, findings with evidence, forecasts,
strategies and EPC, the report with both Scope 2 methods, factors, devices). With ANTHROPIC_API_KEY set it also
stores AI explanations for the largest finding of each rule, in English and Chinese. Static prototypes and reviews
use it instead of running the stack.
The README animation is generated with node scripts/hero/build-hero.mjs (copy in scripts/hero/strings.mjs), the
repository's social preview with node scripts/hero/build-poster.mjs.
See CONTRIBUTING.md and SECURITY.md. Changes are listed in CHANGELOG.md.
Apache License 2.0. See LICENSE.

