# CLAUDE.md ## Project Web app that answers one question with data: for a given property in France, is buying financially better than renting and investing the same cash? It outputs an amortisation schedule, total ownership costs, and breakeven curves under several market hypotheses. This is a financial tool. A wrong number is worse than a slow response, an ugly page, or a missing feature. Correctness and traceable sources come first. I am learning Rust through this project. See "Working with me" below. ## Commands ```bash cargo run -p immo-web # start the server on :3000 cargo watch -x 'run -p immo-web' # live reload during development cargo test --workspace # all tests cargo test -p immo-core # domain tests only, fast cargo fmt --all cargo clippy --workspace --all-targets -- -D warnings ``` Run `cargo clippy` and `cargo test -p immo-core` before telling me a change is finished. ## Architecture boundary Two crates. The boundary is a rule, not a description. `crates/immo-core` holds all financial logic as pure functions over plain structs. - No `tokio`, no `axum`, no `reqwest`, no filesystem, no network access. - Must stay compilable to `wasm32-unknown-unknown`. After adding any dependency, verify with `cargo check -p immo-core --target wasm32-unknown-unknown`. - Time is a parameter. Never call `Utc::now()` or read the system clock inside `immo-core`. `crates/immo-web` holds HTTP, HTML rendering, and input parsing. It contains no financial arithmetic. If a computation is tempting to write inline in a handler, it belongs in `immo-core`. ## Stack, pinned - axum 0.8. Path parameters use `{param}`, **not** `:param` — that is 0.7 syntax and will not compile. - `#[async_trait]` is not needed on `FromRequest` / `FromRequestParts` in 0.8. Do not add it. - askama for templates, tower-http for static files and compression, serde, rust_decimal. - Server-rendered HTML. No npm, no bundler, no JS framework. Charts are a CDN `