Skip to content

Commit e15273b

Browse files
committed
fix: update README.md content and remove unused architecture SVG
1 parent a8fbd7e commit e15273b

2 files changed

Lines changed: 190 additions & 260 deletions

File tree

README.md

Lines changed: 190 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
<p align="center">
2-
<picture>
3-
<source media="(prefers-color-scheme: dark)" srcset="assets/aimdb-logo.svg">
4-
<source media="(prefers-color-scheme: light)" srcset="assets/aimdb-logo.svg">
5-
<img src="assets/aimdb-logo.svg" alt="AimDB" width="450" style="background-color: white; padding: 20px; border-radius: 12px;">
6-
</picture>
2+
<img src="assets/aimdb-logo.svg" alt="AimDB" width="450">
73
</p>
84
<p align="center">
9-
<strong>Dataflow engine for distributed systems.</strong><br>
10-
<strong>MCU to Cloud. Same API.</strong>
5+
<strong>Distributed by design. Data-driven by default.</strong>
116
</p>
127
<p align="center">
138
<a href="https://github.com/aimdb-dev/aimdb/stargazers/" target="_blank">
@@ -27,55 +22,212 @@
2722
</a>
2823
</p>
2924

30-
Write your data pipeline once. Run it on microcontrollers, edge gateways or Kubernetes — no code changes. AimDB's portable data contracts handle serialization, transforms and schema evolution across all runtimes.
25+
AimDB turns data contracts into the architecture. Define your schemas once — with built-in versioning, observability and serialization — and deploy them unchanged across microcontrollers, edge gateways, Kubernetes and the browser.
3126

32-
<p align="center">
33-
<img src="assets/architecture.svg" alt="AimDB Architecture" width="700">
34-
</p>
27+
---
28+
29+
### Vision
30+
31+
A future where every system — from a $2 sensor to a global fleet — shares one data language. Contracts define how data moves, evolves and is observed. Infrastructure adapts to the data, not the other way around.
32+
33+
---
34+
35+
### Design Philosophy
36+
37+
In a data-driven architecture, every design decision starts with the data, not the service that produces it.
38+
39+
**Records declare their own semantics.** When you register a record in AimDB, you choose a buffer type that defines how the data moves:
40+
41+
| Buffer | Semantics | Use Cases |
42+
|--------|-----------|-----------|
43+
| **SPMC Ring** | Bounded stream with independent consumers | Sensor telemetry, event logs, interaction streams |
44+
| **SingleLatest** | Only the current value matters | Feature flags, configuration, UI state |
45+
| **Mailbox** | Latest instruction wins | Device commands, actuation, RPC |
46+
47+
These are the three universal primitives of data movement — portable, typed and runtime-agnostic.
48+
49+
**Observability becomes automatic.** A record that exists is observable by definition. Every producer and consumer relationship is declared in the builder, not discovered through instrumentation.
50+
51+
**Synchronization becomes declarative.** You don't build a sync layer between your MCU, edge gateway and cloud backend. You declare a record with connector metadata on its key and the same typed data flows across all environments without translation.
52+
53+
**Cross-cutting concerns derive from the schema.** Instead of adding observability libraries, feature flag SDKs and experiment frameworks as separate integrations, they become intrinsic properties of records — declared once, applied everywhere.
54+
55+
---
56+
57+
### How It Works
58+
59+
Define your contracts, choose buffer semantics and wire up connectors — all in one builder block:
60+
61+
```rust
62+
// A sensor node: produce temperature readings, publish over MQTT
63+
builder.configure::<Temperature>("sensor::temp", |reg| {
64+
reg.buffer(BufferCfg::SpmcRing { capacity: 256 })
65+
.source(|ctx, producer| async move {
66+
loop {
67+
let reading = read_sensor().await;
68+
producer.send(Temperature::set(reading, now())).await.ok();
69+
ctx.sleep(Duration::from_secs(1)).await;
70+
}
71+
})
72+
.link_to("mqtt://sensors/temperature")
73+
.with_serializer(Temperature::to_bytes)
74+
.finish();
75+
});
76+
77+
// An edge gateway: receive from MQTT, observe and forward
78+
builder.configure::<Temperature>("gateway::temp", |reg| {
79+
reg.buffer(BufferCfg::SingleLatest)
80+
.link_from("mqtt://sensors/temperature")
81+
.with_deserializer(Temperature::from_bytes)
82+
.tap(log_tap::<Temperature>("edge")) // [edge] 22.5 °C
83+
.finish();
84+
});
85+
```
86+
87+
Transport topics can be passed as strings to `link_to` / `link_from`, or declared on key enums with `#[link_address = "mqtt://..."]` and resolved at runtime. No separate instrumentation. No SDK integration. No sync code.
88+
89+
---
90+
91+
### Data Contracts
92+
93+
Data contracts are the heart of AimDB. A contract is a plain Rust struct that carries its own identity, version and capabilities — the single source of truth from sensor firmware to browser UI.
94+
95+
```rust
96+
use aimdb_data_contracts::{SchemaType, Settable};
97+
use serde::{Deserialize, Serialize};
98+
99+
#[derive(Debug, Clone, Serialize, Deserialize)]
100+
pub struct Temperature {
101+
pub celsius: f32,
102+
pub timestamp: u64,
103+
}
104+
105+
impl SchemaType for Temperature {
106+
const NAME: &'static str = "temperature";
107+
const VERSION: u32 = 1;
108+
}
109+
110+
impl Settable for Temperature {
111+
type Value = f32;
112+
fn set(value: Self::Value, timestamp: u64) -> Self {
113+
Self { celsius: value, timestamp }
114+
}
115+
}
116+
```
117+
118+
This struct compiles for `no_std` embedded targets and standard Rust alike. `SchemaType` gives the record its identity and version. `Settable` provides a canonical constructor so producers can create records from a raw value — this is the interface used by `producer.send(Temperature::set(reading, now()))` in the builder.
119+
120+
#### Contract Attributes
121+
122+
Contracts gain capabilities through trait implementations. Each trait is a compile-time declaration of what a contract *can do*, not a runtime configuration:
123+
124+
| Attribute | Trait | What It Enables |
125+
|-----------|-------|-----------------|
126+
| **Settable** | `Settable` | Canonical constructor from a raw value — the interface behind `producer.send(T::set(value, ts))`. |
127+
| **Streamable** | `Streamable` | Cross-boundary transport — WASM, WebSocket, CLI. One registry, zero parallel type systems. |
128+
| **Migratable** | `MigrationStep` | Bidirectional schema evolution with typed up/down transforms and chained version steps. |
129+
| **Observable** | `Observable` | Signal extraction for thresholds, logging and monitoring. Icon, unit and `format_log()` built in. |
130+
| **Linkable** | `Linkable` | Wire-format serialization for connectors — MQTT, KNX and any future transport. |
131+
| **Simulatable** | `Simulatable` | Realistic test data generation with random walks, trends and configurable parameters. |
132+
133+
For example, `Observable` turns a contract into a loggable, monitorable signal:
134+
135+
```rust
136+
impl Observable for Temperature {
137+
type Signal = f32;
138+
const ICON: &'static str = "thermometer";
139+
const UNIT: &'static str = "°C";
140+
141+
fn signal(&self) -> f32 { self.celsius }
142+
143+
fn format_log(&self, node_id: &str) -> String {
144+
format!("[{}] {:.1} °C", node_id, self.celsius)
145+
}
146+
}
147+
```
148+
149+
Each trait you implement unlocks a capability — contracts without `Observable` simply can't be tapped; contracts without `Linkable` can't be wired to connectors. The type system enforces what your data can do.
150+
151+
#### Platform-Agnostic by Design
152+
153+
The same contract works across all runtimes without modification:
154+
155+
```
156+
┌───────────────────────────────────────────────────────────────────────────────┐
157+
│ Temperature Contract │
158+
├───────────────────┬───────────────────┬───────────────────┬───────────────────┤
159+
│ MCU (Embassy) │ Edge (Tokio) │ Cloud (Tokio) │ Browser (WASM) │
160+
│ no_std + alloc │ std │ Kubernetes │ wasm32 │
161+
│ Cortex-M4 │ Linux / RPi │ Full featured │ Single-threaded │
162+
└───────────────────┴───────────────────┴───────────────────┴───────────────────┘
163+
```
164+
165+
The Rust type system enforces correctness at compile time. The dataflow engine's buffer semantics enforce flow guarantees at runtime. Connectors wire everything to your infrastructure without an integration layer.
35166

36167
---
37168

38169
### Getting Started
39170

40-
**See it live** — explore a running sensor mesh at [aimdb.dev](https://aimdb.dev)
171+
#### 1. See it live
172+
173+
Explore a running sensor mesh — no setup required:
41174

42175
<p align="center">
43176
<a href="https://aimdb.dev">
44177
<img src="assets/demo.gif" alt="AimDB Live Demo" width="600">
45178
</a>
46179
</p>
47180

48-
**Run locally** — full MCU → edge → cloud mesh in Docker:
181+
> **[aimdb.dev](https://aimdb.dev)** — live weather stations streaming typed contracts across MCU, edge and cloud.
182+
183+
#### 2. Run locally
184+
185+
Spin up a full MCU → edge → cloud mesh with one command:
49186

50187
```bash
51188
cd examples/weather-mesh-demo
52189
docker compose up
53190
```
54191

55-
Then ask VS Code Copilot: *"What's the current temperature from station ...?"* ([MCP setup required](examples/weather-mesh-demo/))
192+
This starts three weather stations, an MQTT broker and a central hub — all wired together with typed data contracts.
193+
194+
#### 3. Explore with AI
195+
196+
With the mesh running, connect an MCP-compatible editor to query your data in natural language:
56197

57198
<p align="center">
58199
<img src="assets/copilot-communication.gif" alt="AimDB MCP Live Demo" width="600">
59200
</p>
60201

61-
**Learn more:**
62-
- [Quick Start Guide](https://aimdb.dev/docs/getting-started) — Dependency setup and API basics
63-
- [Data Contracts](https://aimdb.dev/docs/data-contracts) — Type-safe schemas
64-
- [Connectors](https://aimdb.dev/docs/connectors) — MQTT, KNX and more
65-
- [Deployment](https://aimdb.dev/docs/deployment) — Running on MCU, edge and cloud
66-
- [API Reference](https://docs.rs/aimdb-core) — Full Rust API documentation
202+
Install the MCP server and add it to your workspace:
67203

68-
---
204+
```bash
205+
cargo install aimdb-mcp
206+
```
69207

70-
### Why AimDB?
208+
`.vscode/mcp.json`:
71209

72-
A real-time data runtime that adapts to your infrastructure, not the other way around.
210+
```json
211+
{
212+
"servers": {
213+
"aimdb": {
214+
"type": "stdio",
215+
"command": "${userHome}/.cargo/bin/aimdb-mcp"
216+
}
217+
}
218+
}
219+
```
73220

74-
| Problem | AimDB Solution |
75-
|---------|----------------|
76-
| **Runs Where Data Starts** | From $2 MCUs to Kubernetes clusters. Deploy the same code anywhere, process data at the source. |
77-
| **Same API Everywhere** | Tokio + Embassy compatible, embedded-friendly, `no_std`-ready. One interface across all your runtimes. |
78-
| **Built for Continuous Change** | Unified data layer with schema evolution built in. Your data pipelines adapt as fast as your business. |
221+
Then ask: *"What's the current temperature from station alpha?"* — see the [MCP server docs](tools/aimdb-mcp/) for Claude Desktop and other editors.
222+
223+
#### 4. Build your own
224+
225+
- [Quick Start Guide](https://aimdb.dev/docs/getting-started) — Dependencies, platform setup and your first contract
226+
- [Data Contracts](https://aimdb.dev/docs/data-contracts) — Type-safe schemas with built-in capabilities
227+
- [Connectors](https://aimdb.dev/docs/connectors) — MQTT, KNX, WebSocket and more
228+
- [Deployment](https://aimdb.dev/docs/deployment) — Running on MCU, edge, cloud and browser
229+
- [API Reference](https://docs.rs/aimdb-core) — Full Rust API documentation
230+
- [Blog](https://aimdb.dev/blog) — News, tutorials and insights from the AimDB team
79231

80232
---
81233

@@ -85,20 +237,20 @@ A real-time data runtime that adapts to your infrastructure, not the other way a
85237
|----------|-------|--------|----------|
86238
| **MQTT** | `aimdb-mqtt-connector` | ✅ Ready | std, no_std |
87239
| **KNX** | `aimdb-knx-connector` | ✅ Ready | std, no_std |
88-
| **HTTP/REST** | | 🔨 Building | std |
240+
| **WebSocket** | `aimdb-websocket-connector` | ✅ Ready | std, wasm |
89241
| **Kafka** || 📋 Planned | std |
90242
| **Modbus** || 📋 Planned | std, no_std |
91243

92244
---
93245

94246
### Platform Support
95247

96-
| Target | Runtime | Features | Footprint |
97-
|--------|---------|----------|-----------|
98-
| **ARM Cortex-M** (STM32H5, STM32F4) | Embassy | no_std, async | ~50KB+ |
99-
| **ARM Cortex-M** (STM32H5, STM32F4) | FreeRTOS | 📋 Planned | |
100-
| **Linux Edge Devices** | Tokio | Full std | ~10MB+ |
101-
| **Containers/K8s** | Tokio | Full std | ~10MB+ |
248+
| Target | Runtime | Adapter | Features | Footprint |
249+
|--------|---------|---------|----------|-----------|
250+
| **ARM Cortex-M** (STM32H5, STM32F4) | Embassy | `aimdb-embassy-adapter` | no_std, async | ~50KB+ |
251+
| **Linux Edge** (RPi, gateways) | Tokio | `aimdb-tokio-adapter` | Full std | ~10MB+ |
252+
| **Containers / K8s** | Tokio | `aimdb-tokio-adapter` | Full std | ~10MB+ |
253+
| **Browser / SPA** | WASM | `aimdb-wasm-adapter` | wasm32, single-threaded | ~2MB+ |
102254

103255
---
104256

@@ -119,5 +271,7 @@ Want to contribute? See the [contributing guide](CONTRIBUTING.md). We have [good
119271
---
120272

121273
<p align="center">
122-
<strong>Write once. Deploy anywhere. Pay only where it makes sense.</strong>
274+
<strong>Define once. Deploy anywhere. Observe everything.</strong>
275+
<br><br>
276+
<a href="https://aimdb.dev/docs/getting-started">Get started</a> · <a href="https://aimdb.dev">Live demo</a> · <a href="https://github.com/aimdb-dev/aimdb/discussions">Join the discussion</a>
123277
</p>

0 commit comments

Comments
 (0)