add README and MIT license
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Gabriel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
161
README.md
Normal file
161
README.md
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
# K-Frame
|
||||||
|
|
||||||
|
IoT dashboard system. A server aggregates data from external sources (weather APIs, media players, RSS feeds, webhooks) and pushes rendered updates to ESP32 display clients over TCP.
|
||||||
|
|
||||||
|
**Server** polls data sources, projects values through configurable widget mappings, computes layouts, and broadcasts binary frames to connected clients. Configuration via REST API + web UI.
|
||||||
|
|
||||||
|
**Clients** receive structured data + layout trees, compute bounding boxes, format text per display hint rules, and render to hardware. The client domain is chip-agnostic — the same rendering engine runs on ESP32 (ILI9341 TFT) and desktop (terminal).
|
||||||
|
|
||||||
|
**Web UI** (SPA) configures data sources, widgets, layouts, themes, and presets. Includes a live layout preview that mirrors what the physical display shows.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Hexagonal / ports-and-adapters with full CQRS. Domain logic has zero framework dependencies. Static dispatch everywhere (no `Box<dyn>`, no trait objects).
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────── Server ───────────────────┐
|
||||||
|
│ domain/ entities, value objects, │
|
||||||
|
│ ports (traits) │
|
||||||
|
│ application/ use cases, data projection │
|
||||||
|
│ bootstrap/ composition root, polling │
|
||||||
|
│ │
|
||||||
|
│ adapters/ │
|
||||||
|
│ config-sqlite persistence │
|
||||||
|
│ http-api REST API (Axum) │
|
||||||
|
│ tcp-server binary protocol broadcast │
|
||||||
|
│ http-json external API polling │
|
||||||
|
│ media, rss source-specific adapters │
|
||||||
|
│ auth argon2 + JWT │
|
||||||
|
├─────────────────── Shared ───────────────────┤
|
||||||
|
│ protocol/ wire types, postcard serde │
|
||||||
|
│ api-types/ REST DTOs │
|
||||||
|
├─────────────────── Client ───────────────────┤
|
||||||
|
│ client-domain/ layout engine, render engine │
|
||||||
|
│ markup parser, scroll state │
|
||||||
|
│ client-application/ message handling │
|
||||||
|
│ client-esp32/ ESP32 firmware (ILI9341) │
|
||||||
|
│ client-desktop/ terminal debug client │
|
||||||
|
├──────────────────── SPA ─────────────────────┤
|
||||||
|
│ spa/ React + TanStack Router │
|
||||||
|
│ shadcn/ui + Tailwind │
|
||||||
|
└──────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key design decisions
|
||||||
|
|
||||||
|
- **postcard + serde** for the wire protocol — compact varint encoding, `no_std` compatible, no codegen
|
||||||
|
- **Static dispatch** — port traits used as generic bounds, not trait objects. Composition root resolves all types
|
||||||
|
- **Event-driven CQRS** — config mutations emit domain events, read model projected in memory
|
||||||
|
- **Domain-owned rendering** — client-domain owns text wrapping, alignment, color markup, scroll. DisplayPort is a thin pixel-pusher (`draw_text_span`, `fill_rect`, `flush`)
|
||||||
|
- **WiFi provisioning** — ESP32 boots into AP captive portal if no config in NVS, auto-falls back on WiFi failure
|
||||||
|
|
||||||
|
See `docs/adr/` for architectural decision records and `CONTEXT.md` for the domain glossary.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Data sources**: HTTP/JSON, weather, media (Subsonic/Navidrome), RSS, webhooks
|
||||||
|
- **Layout engine**: flexbox-like containers (row/column, fixed/flex sizing, gap, padding, justify-content, align-items)
|
||||||
|
- **Theming**: 5 configurable colors (primary, secondary, accent, text, background), live push to clients
|
||||||
|
- **Rich text**: inline color markup (`{primary}text{/}`, `{#FF0000}hex{/}`)
|
||||||
|
- **Overflow scroll**: bounce animation when content exceeds widget bounds, speed auto-derived from overflow
|
||||||
|
- **Captive portal**: ESP32 AP mode with DNS + HTTP config form for WiFi provisioning
|
||||||
|
- **Auth**: argon2 password hashing, JWT tokens, protected API routes
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Rust** (stable) — server, desktop client, shared crates
|
||||||
|
- **Rust ESP32 toolchain** — `espup`, xtensa target. See [esp-rs book](https://docs.esp-rs.org/book/)
|
||||||
|
- **Node.js / Bun** — SPA development
|
||||||
|
- **SQLite** — server persistence (created automatically)
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Clone and configure
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env — set JWT_SECRET and KFRAME_ENCRYPTION_KEY
|
||||||
|
|
||||||
|
# 2. Start the server
|
||||||
|
make server
|
||||||
|
|
||||||
|
# 3. Start the SPA dev server (separate terminal)
|
||||||
|
cd spa && bun install && bun run dev
|
||||||
|
# Open http://localhost:5173
|
||||||
|
|
||||||
|
# 4. Register an account (first launch = setup mode)
|
||||||
|
# 5. Add a data source, create widgets, build a layout
|
||||||
|
```
|
||||||
|
|
||||||
|
### ESP32 client
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build firmware
|
||||||
|
make esp-build
|
||||||
|
|
||||||
|
# Flash (default port: /dev/ttyACM0)
|
||||||
|
make esp-flash
|
||||||
|
|
||||||
|
# Flash with custom port
|
||||||
|
make esp-flash ESP_PORT=/dev/ttyUSB0
|
||||||
|
|
||||||
|
# Flash and monitor serial output
|
||||||
|
make esp-run
|
||||||
|
|
||||||
|
# On first boot: connect to "KFrame-Setup" WiFi, enter credentials in captive portal
|
||||||
|
```
|
||||||
|
|
||||||
|
### Desktop client
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make desktop
|
||||||
|
# Connects to localhost:2699, prints render commands to terminal
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Full check suite (fmt + clippy + test)
|
||||||
|
make check
|
||||||
|
|
||||||
|
# Auto-fix formatting and clippy warnings
|
||||||
|
make fix
|
||||||
|
|
||||||
|
# Run tests only
|
||||||
|
make test
|
||||||
|
|
||||||
|
# SPA type checking
|
||||||
|
cd spa && bun run typecheck
|
||||||
|
```
|
||||||
|
|
||||||
|
### Project structure
|
||||||
|
|
||||||
|
| Path | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `crates/domain/` | Entities, value objects, port traits |
|
||||||
|
| `crates/application/` | Use cases (ConfigService, DataProjection) |
|
||||||
|
| `crates/protocol/` | Wire types, encode/decode (`no_std`) |
|
||||||
|
| `crates/bootstrap/` | Server composition root |
|
||||||
|
| `crates/adapters/` | All port implementations |
|
||||||
|
| `crates/client-domain/` | Display-agnostic rendering engine |
|
||||||
|
| `crates/client-application/` | Client message handling |
|
||||||
|
| `crates/client-esp32/` | ESP32 firmware |
|
||||||
|
| `crates/client-desktop/` | Terminal debug client |
|
||||||
|
| `crates/api-types/` | REST API DTOs |
|
||||||
|
| `spa/` | React SPA |
|
||||||
|
| `docs/adr/` | Architecture decision records |
|
||||||
|
| `CONTEXT.md` | Domain glossary |
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork the repo
|
||||||
|
2. Create a feature branch
|
||||||
|
3. Run `make check` before pushing — CI runs the same checks
|
||||||
|
4. Open a PR with a clear description of what changed and why
|
||||||
|
|
||||||
|
The domain glossary in `CONTEXT.md` defines the canonical language. Use it in code, commits, and PRs. If you're adding a new concept, update the glossary.
|
||||||
|
|
||||||
|
Architecture decisions are documented in `docs/adr/`. If your change involves a hard-to-reverse design choice, write an ADR.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE)
|
||||||
Reference in New Issue
Block a user