add README and MIT license

This commit is contained in:
2026-06-19 03:28:41 +02:00
parent fe59b68c37
commit e8b968bcd1
2 changed files with 182 additions and 0 deletions

21
LICENSE Normal file
View 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
View 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)