Quick Start
1. Start the server
xcon-db-server -sample-config > xcon-db.toml
# edit xcon-db.toml: set root, listen addresses and the [admin] password
xcon-db-server -config xcon-db.toml
The [admin] user in the config file always exists — that is the whole
bootstrap (the postgres/sa pattern).
2. Create a database and a user
Every tenant is one database — one self-contained directory. Connect as the admin and build it over SQL:
psql "postgres://xcon:change-me@127.0.0.1:5432/xcon"
CREATE DATABASE demo;
CREATE USER demo PASSWORD 'secret' DATABASE demo;
3. Create a table
Any PostgreSQL client works. With psql:
psql "postgres://demo:secret@127.0.0.1:5432/demo"
CREATE TABLE telemetry (
speed DOUBLE FILL HOLD STALENESS 60 s,
event TEXT FILL NONE
) WITH (RETENTION 90 d);
entity (which device) and ts (Unix milliseconds) are implicit columns on every table.
4. Write and read
INSERT INTO telemetry (entity, ts, speed) VALUES
('veh-1', 1700000000000, 50),
('veh-1', 1700000060000, 62);
INSERT INTO telemetry (entity, ts, event) VALUES
('veh-1', 1700000030000, 'brake');
SELECT * FROM telemetry WHERE entity = 'veh-1';
Note what comes back: at ts = 1700000030000 the speed column reads 50 — the last observed value, carried forward because the channel was declared FILL HOLD. The event column is null everywhere except its exact timestamps, because FILL NONE refuses to invent data. This is forward-fill, the heart of the read model.
5. Or ingest over ILP
# InfluxDB line protocol, straight from a device or Telegraf
# (config: listen.ilp = ":9009", listen.ilp_db = "demo"):
printf 'telemetry,entity=veh-1 speed=52.5 1700000120000000000\n' \
| nc 127.0.0.1 9009