Drill Cloud v2
Optimized Drill Cloud backend for high-volume time-series reads on PostgreSQL + TimescaleDB.
Why v2
The existing history table already has tens of millions of rows. The expensive path is not the number of tags, but dense time-series scans for charts. v2 stores raw points in a Timescale hypertable, keeps latest values in a small current_values table, and serves charts from raw data or continuous aggregates depending on the requested range.
Default chart budget is 2000 points per series.
Run locally
With Docker:
cp .env.example .env
docker compose up -d
npm install
npm run migrate
npm run start:dev
Default local database:
postgres://postgres:postgres@localhost:5435/drill_cloud_v2
Without Docker, use a locally installed PostgreSQL + TimescaleDB and copy .env.local.example to .env.
See LOCAL_NO_DOCKER.md.
API
Health
GET /health
Ingest array
POST /ingest
Content-Type: application/json
x-api-key: <INGEST_API_KEY if configured>
[
{
"edge": "roman",
"tag": "BN1_24V_Supply_Fault",
"time": "2026-06-10T22:29:05.098Z",
"value": 1
}
]
timestamp as Unix milliseconds is also accepted instead of time.
Ingest edge values
POST /ingest/roman
Content-Type: application/json
{
"timestamp": 1781123345098,
"values": {
"BN1_24V_Supply_Fault": 1,
"Term_Drehz_IW_Motor": 1028
}
}
Current values
GET /current?edge=roman
GET /current?edge=roman&tags=tag1,tag2
History for charts
GET /history?edge=roman&tags=BN1_24V_Supply_Fault&from=2026-04-18T00:00:00Z&to=2026-04-26T00:00:00Z
Optional parameters:
targetPoints- 100..2000, default 2000.valueMode-avg,last,first,min,maxfor aggregate layers.tags- comma-separated tag ids. If omitted, v2 usesedge_tag.
The response includes:
source:raw,1m,5m,1h,1d, orlatest.series[].points[]: compact chart points shaped as{ "t": unixMs, "v": value }.- Aggregate points also include
first,min,max,avg,last,count.
Data model
Hot path tables:
history_points- Timescale hypertable partitioned bytime.current_values- latest value per(edge_id, tag_id).edge,tag,edge_tag- catalog and series membership.
Continuous aggregates:
history_1mhistory_5mhistory_1hhistory_1d
Production notes
- Use TimescaleDB, not plain PostgreSQL, before running migrations.
- Keep
INGEST_API_KEYset in production. - Run chart queries with explicit
tagswhenever the UI knows selected series. - For historical import from the old database, bulk copy into
history_points, then refresh continuous aggregates.