Add instructions for Claude

This commit is contained in:
2026-03-07 13:53:36 -05:00
parent 002f85aabc
commit 3ca4bda1e2

122
CLAUDE.md Normal file
View File

@@ -0,0 +1,122 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
This is a Rust monorepo. The primary active project is **Visions**, a tabletop RPG game management application with WebSocket-based real-time communication. It uses:
- **Server**: Axum web framework with SQLite (rusqlite)
- **UI**: Yew (WebAssembly) with yew-router
- **Shared types**: visions-types crate shared between server and UI
- **Component library**: glimmer-yew provides reusable Yew components
## Build Commands
```bash
# Build server
cargo build -p visions-server
# Build UI (requires trunk)
cd visions/ui && trunk build
# Run server (requires env vars)
DATABASE_PATH=... RELYING_PARTY=... RELYING_PARTY_ORIGIN=... PWA_BASE_URL=... cargo run -p visions-server
# Run all tests
cargo test
# Run specific test
cargo test -p visions-core test_name
# Run integration tests for server
cargo test -p visions-server --test integrations
```
## Architecture
### Visions Crates
- **visions/core**: Business logic, database layer, App struct. Uses nested `Result<Result<T, Error>, Fatal>` pattern for error handling.
- **visions/server**: Axum HTTP/WebSocket handlers and routing. Handlers use `http_adapter` to convert nested results to HTTP responses.
- **visions/types**: Shared types between server and UI. Uses `identifier!` macro to generate ID types (UserId, GameId, etc.).
- **visions/ui**: Yew WebAssembly frontend. Uses `StateProvider` for app state, `StyleProvider` for theming.
### glimmer-yew
Reusable Yew component library with styling via `stylist`. Components use `Stylesheet` context for theming. Key exports in `prelude` module.
## Rust Style Guidelines
### Error Handling
Use nested results to separate recoverable errors from fatal errors:
```rust
fn fallible() -> Result<Result<(), Error>, Fatal>
fn search() -> Result<Option<()>, Fatal>
```
Fatal errors should never be caught except at the top level. Recoverable errors should never be promoted to fatal.
### Let/Else Bindings
Prefer let/else over match for unwrapping:
```rust
// Preferred
let Some(game) = db.game(&image.game)? else {
return Ok(Err(Error::NotFound(image.game.as_str().to_string())));
};
// Avoid
let game = match db.game(&image.game)? {
Some(game) => game,
None => return Ok(Err(Error::NotFound(image.game.as_str().to_string()))),
};
```
### Test Style
Tests use SCENARIO/GIVEN/WHEN/THEN comments and `cool_asserts::assert_matches!`:
```rust
/// SCENARIO: Description
/// GIVEN: Preconditions
/// WHEN: Action
/// THEN: Expected outcome
#[tokio::test]
async fn test_name() {
// GIVEN: ...
let support = TestSupport::new().await;
// WHEN: ...
let result = support.app.some_action().await;
// THEN: ...
assert_matches!(result, Ok(Ok(value)) => {
assert_eq!(value.field, expected);
});
}
```
## Yew Component Guidelines (glimmer-yew)
### Naming
- Name components naturally (e.g., `Button`, not `ButtonComponent`)
- Properties struct: `<ComponentName>Props`
### Properties
- Use `AttrValue` for string properties
- Use `Prop<T>` wrapper for sizable non-string properties
- Always accept `#[prop_or_default] pub class: Classes`
- Callbacks: `on_<action>` with `#[prop_or(Callback::from(|_| {}))]`
- Optional properties: `#[prop_or_default]`
### Cloning in Callbacks
Use the `clone!` macro from glimmer-yew:
```rust
use glimmer_yew::clone;
let on_click = Callback::from(clone!(state, move |_| {
state.set(new_value);
}));
// Multiple values
clone!((state, props), move |_| { ... })
```
### Styling
- Components should have no margin
- Avoid CSS nesting except for pseudo-selectors
- Use `stylist::css!` macro with stylesheet tokens from context