yggdrasil/AGENTS.md

4.7 KiB

AGENTS.md

Development Commands

# 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-editortailwindcssdx 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:

./migrate.sh       # preferred: auto-creates DB, runs all migrations in order
# or manually:
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:

#[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

# 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.