diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d806c58 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,129 @@ +# AGENTS.md + +## Development Commands + +```bash +# Dev server — runs tailwindcss watch + dx serve (needs PostgreSQL running) +make dev + +# Production build — builds editor, compiles CSS, then dx build --release +make build + +# Just CSS +make css # one-shot +make css-watch # watch mode + +# Rust only (no CSS/editor) +cargo build +cargo clippy +cargo test +dx check # Dioxus type-check +dx serve # Dev server without Tailwind watch +``` + +**Command order matters for production**: `make build` internally runs `build-editor` → `tailwindcss` → `dx build --release`. Do not run `dx build --release` alone if you need the editor or CSS. + +## Prerequisites + +- Rust 1.95+ with `wasm32-unknown-unknown` target +- `dx` CLI (`cargo install dioxus-cli`) +- `tailwindcss` CLI v4 (standalone binary) +- PostgreSQL running locally + +## Environment + +Create `.env` (not committed — see `.env.example`): + +``` +DATABASE_URL=postgres://postgres:postgres@localhost:5432/yggdrasil +RUST_LOG=info +``` + +Run migrations before first dev server start: + +```bash +psql $DATABASE_URL -f migrations/001_init.sql +``` + +## Architecture: Conditional Compilation + +This is a Dioxus 0.7 fullstack project with **two independent gates**. Getting this wrong is the most common source of compilation errors. + +| Gate | Applies to | Used for | +|------|-----------|----------| +| `#[cfg(feature = "server")]` | Server binary only | Database, env loading, background tasks, server functions body | +| `#[cfg(target_arch = "wasm32")]` | WASM frontend only | localStorage, DOM APIs, cookie manipulation, web_sys calls | + +**Critical**: `feature = "server"` and `target_arch = "wasm32"` are **mutually exclusive** at build time, but both default features (`web` + `server`) are enabled in `Cargo.toml`. The `dx` CLI handles feature selection during builds. + +**Stub pattern**: `src/db/mod.rs` provides a `DummyPool` when the `server` feature is disabled so the crate still compiles for WASM. Do not remove this. + +**Dead code allowances**: Auth utilities (`password.rs`, `session.rs`) carry `#[allow(dead_code)]` because they are imported by `api/auth.rs` but the compiler sees them as unused in WASM builds where server function bodies are stripped. + +## Server Functions + +Server functions live in `src/api/auth.rs` and use the macro: + +```rust +#[server(Name, "/api")] +pub async fn fn_name(...) -> Result<..., ServerFnError> +``` + +These are callable from both client and server Rust code; Dioxus handles HTTP transport automatically. + +## Tiptap Editor Subproject + +The rich-text editor is a separate Vite project in `libs/tiptap-editor/`. + +- Built as an **IIFE** library exposing `window.TiptapEditor` +- Output goes to `public/tiptap/` +- `make build` runs `npm install && vite build` inside `libs/tiptap-editor` and renames the output file +- The write page (`src/pages/admin/write.rs`) initializes the editor via `js_sys::eval` and polls `window.__tiptap_ready` + +Do not edit files in `public/tiptap/` directly — they are build artifacts. + +## Auth & Session + +- **Registration**: first user becomes `admin`; subsequent registrations are rejected with `"Registration is closed"`. +- **Login**: sets an **HttpOnly** cookie via `FullstackContext::add_response_header` (server-side). +- **Session validation**: `get_current_user` reads the `session` cookie from the request headers and queries `sessions` + `users` tables. +- **Background cleanup**: `tasks::session_cleanup::run_cleanup()` deletes expired sessions every hour on a tokio task. + +## Database + +- PostgreSQL via `tokio-postgres` + `deadpool-postgres` +- Pool is a `LazyLock` global in `src/db/pool.rs`, initialized from `DATABASE_URL` +- Max pool size: 10 + +## Testing & Verification + +```bash +# Standard Rust test suite +cargo test + +# Dioxus type-check (catches component/Router issues) +dx check + +# Lint +cargo clippy +``` + +There are currently no integration tests requiring a database connection. + +## Build Artifacts to Ignore + +The following are generated and gitignored: + +- `public/style.css` — generated by Tailwind +- `public/tiptap/` — generated by Vite from `libs/tiptap-editor/` +- `/dist`, `/.dioxus`, `/target` +- `node_modules` (inside `libs/tiptap-editor/`) + +## rust-analyzer + +`rust-analyzer.toml` excludes generated directories (`node_modules`, `public`, `.dioxus`, `.omc`, `dist`). If rust-analyzer shows spurious errors in generated files, check that the exclusion list is respected by your editor. + +## Notes + +- `rand` + `getrandom` with `js` feature are required for Argon2 salt generation in WASM builds. +- The `#[allow(unused_mut, unused_variables)]` on `Write` component is intentional — the `mut` signals are used inside `#[cfg(target_arch = "wasm32")]` blocks that are stripped in server builds.