should-i-rent/CLAUDE.md
Marcel Enguehard e5400c8992 Set up cargo workspace backbone
Two-crate workspace: immo-core for pure financial logic (wasm-compatible,
no async/IO deps) and immo-web for HTTP and rendering. Both crates are
still cargo-new skeletons; no domain code yet.

Pins the toolchain to 1.97 with rustfmt, clippy and the
wasm32-unknown-unknown target so the core crate's wasm constraint is
checkable locally. Cargo.lock is committed since the workspace ships a
binary.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 20:30:55 +02:00

94 lines
4.4 KiB
Markdown

# 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 `<script>` tag fed
by a JSON endpoint.
Before writing axum code from memory, check the version in `Cargo.toml` and verify the API against
docs.rs for that exact version.
## Domain rules
- Money is `rust_decimal::Decimal` or integer cents. Never `f64`. Never `as` casts between numeric
types in financial code.
- Rates are stored as annual nominal and converted explicitly. Name variables so the period is
unambiguous (`taeg_annual`, `monthly_rate`), never a bare `rate`.
- Keep French domain vocabulary in type and field names: `FraisDeNotaire`, `TaxeFonciere`,
`IndiceReferenceLoyers`, `LoyerDeReferenceMajore`, `ZoneTendue`, `Taeg`. Do not translate them.
- Every hardcoded assumption lives in `crates/immo-core/src/assumptions.rs` with a `///` comment
giving its source and the date it was checked. Nothing hardcoded anywhere else.
- If you do not know a real figure — a barème, a tax rate, a fee schedule, an IRL value — say so and
leave a clearly named placeholder. Do not invent plausible-looking French tax numbers.
- TAEG and taux nominal are different things. Distinguish them explicitly wherever both appear.
## Error handling and tests
- `thiserror` for typed errors in `immo-core`; `anyhow` only at the `immo-web` boundary.
- No `unwrap()`, `expect()`, or `panic!()` outside tests and `main`.
- Every `core` function producing a number the user sees has a known-answer test, with the worked
example stated in the test name or a comment above it.
- Test the amortisation schedule against hand-checked values, never against the implementation's
own output.
## Working with me
I know traits, `Result`, and the borrow checker. I do not know the ecosystem well, and learning it
is half the point of this project.
- When you use a non-obvious idiom — extractors, `Layer`, lifetimes on a struct, `impl Trait` in
return position — explain why in one or two sentences, in chat rather than as a code comment.
- If my request implies an unidiomatic design, say so before implementing it.
- Prefer the simple version over the clever one, and tell me when you deliberately chose the
simple one.
## Do not
- Add a dependency without asking first, including small ones.
- Introduce npm, a bundler, TypeScript, or a frontend framework.
- Write financial logic in `crates/immo-web`.
- Leave commented-out code, or comments that restate what the code does.
- Reformat or restructure files you were not asked to touch.