From e8b968bcd167b7bdc006f86a7648cc6055daba8a Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Fri, 19 Jun 2026 03:28:41 +0200 Subject: [PATCH] add README and MIT license --- LICENSE | 21 +++++++ README.md | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1c8e356 --- /dev/null +++ b/LICENSE @@ -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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c7e6f3 --- /dev/null +++ b/README.md @@ -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`, 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)