# AI Guidelines — Domotique Rust/Leptos ## Project overview Home automation dashboard built with Leptos (full-stack Rust). Exposes a web UI for managing quick links and controlling shutters via HTTP API to IoT devices. Runs as a systemd service with SSR + WASM hydration. ## Tech stack | Layer | Technology | |---|---| | Framework | Leptos 0.6 (SSR + hydration) | | Server | Axum 0.7 + Tokio | | Database | MySQL via SQLx 0.8 (compile-time checked queries) | | Frontend | WASM (wasm-bindgen), Tailwind CSS 4 | | Build | cargo-leptos, Makefile | ## Architecture ### Dual-target compilation - `ssr` feature: binary target, runs Axum, has DB access, pre-renders HTML - `hydrate` feature: lib target compiled to WASM, mounts into DOM Gate all server-only code (database, filesystem, secrets) with `#[cfg(feature = "ssr")]`. ### Directory layout ``` src/ app.rs # App component, router, nav lib.rs # WASM entry point (hydrate feature) main.rs # Binary entry point (ssr feature) setup.rs # Axum server initialization database.rs # Global MySqlPool (OnceLock) models/ # Data models + SQL queries routes/ # Page components + server functions migrations/ # SQLx migrations (timestamp-named) style/ # Compiled Tailwind output input.css # Tailwind source ``` ### Data flow 1. Page component defines a `Resource` that calls a server function 2. Server function (`#[server]`) queries the DB via `sqlx::query!` 3. Mutations use `create_server_action` or `create_action` 4. After mutation, increment a version signal to trigger resource refetch ## Coding conventions ### Language & naming - UI labels and user-facing strings are in **French** (e.g., `Liens`, `Volets`) - Rust identifiers follow standard conventions: `snake_case` for functions/variables, `PascalCase` for types and components - Server function names are descriptive PascalCase (e.g., `GetLinksAction`, `LinkAction`) ### Components - One `#[component]` per logical unit, small and single-responsibility - Use `create_rw_signal` / `create_signal` for local state - Use `Resource` for async data; include a version signal for cache invalidation - Modal pattern for forms: single component toggled between create/edit mode ### Server functions ```rust #[server(MyAction, "/api", "GetJson")] // or "Cbor" for mutations pub async fn my_action(...) -> Result { // DB access gated by ssr feature implicitly via #[server] } ``` - Return `Result` - Log errors with `tracing::error!` before returning a generic error to the client - Never expose internal error details to the client ### Database - Use `sqlx::query!` / `sqlx::query_as!` for compile-time checked SQL - Access the pool via the global `get_db()` helper in `database.rs` - Keep queries in the model file for the relevant type (`models/link.rs`) - Connection pool max: 4 connections — avoid holding connections across await points ### Styling - Tailwind utility classes only — no custom CSS except CSS variables in `input.css` - Dark-first design; use `dark:` variants when needed - Custom color tokens (defined in `input.css`, OKLCH color space): - `prim`, `prim-light` — primary accent - `second`, `second-dark` — secondary - `third`, `third-light` — tertiary accent - `fourth`, `green` — utility - Responsive breakpoints: `xs:`, `sm:`, `md:`, `lg:` ### Error handling - Server functions: `Result`, log then return generic message - Components: handle `None` / error states explicitly in the view - Avoid `unwrap()` in production paths; use `?` or explicit error handling ## Development workflow ```bash # Start dev server (auto-reload) cargo leptos watch # Watch Tailwind in parallel npx tailwindcss -i input.css -o ./style/output.css --watch # Run DB migrations sqlx migrate run # Production deploy make install # builds Tailwind + WASM + binary, restarts systemd service ``` Environment variables are loaded from `.env` (`DATABASE_URL` required). ## Key patterns to follow - **No new dependencies** without a clear reason — the stack is intentionally minimal - **No JavaScript** — all interactivity through Leptos/WASM - **Keep components in `routes/`** unless genuinely reusable across multiple pages - **New DB tables** require a migration file in `migrations/` - **External API calls** (e.g., shutters) go through server functions, never from WASM directly - **Do not add features** beyond what is asked; this is a personal tool, not a framework