add ai guidline
This commit is contained in:
126
AI.md
Normal file
126
AI.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 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<T, ServerFnError> {
|
||||
// DB access gated by ssr feature implicitly via #[server]
|
||||
}
|
||||
```
|
||||
|
||||
- Return `Result<T, ServerFnError>`
|
||||
- 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<T, ServerFnError>`, 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
|
||||
Reference in New Issue
Block a user