# Code Style ## Rust - Two spaces for indentation (not four) - No minimum supported Rust version; use latest stable features freely - `#[macro_use] extern crate serde_derive;` is used in binary crates; library crates use `use serde_derive::{Serialize, Deserialize};` - Never use `println!` or `eprintln!` outside of tests; use `log` crate macros (`info!`, `warn!`, `error!`, `debug!`, `trace!`) instead - Use `anyhow::Result` / `AnyhowResult` for fallible functions in application code; new database queries should use `Result` instead - SQLx: MySQL queries belong in the `mysql_queries` crate. Do NOT write `sqlx::query!` / `sqlx::query()` in application/service crates (e.g. `storyteller-web`, which has zero direct SQLx queries) — add or reuse a function in `mysql_queries` and call it. The compile-time `query!` / `query_as!` macro conventions for that crate are documented in `crates/schema/database/mysql_queries/CLAUDE.md`. - Enum Display/Debug: use `impl_enum_display_and_debug_using_to_str!` macro, not `derive_more::Display` (CLion doesn't understand it) - Fields that are optional use the `maybe_` prefix: `maybe_creator_user_token`, `maybe_prompt_token` - When implementing `fmt::Display` for error types, use the pattern: `write!(f, "{:?}", self)` ## File Layout (Top-to-Bottom Reading Order) Organize code so a human reading top-to-bottom encounters the most important things first and can drill down into details only when curious. Think of it like a newspaper: headline first, then the story, then the fine print. ### Ordering within a file 1. **Constants** at the top, right after imports. 2. **The primary public type** (the main struct/enum the file is about) comes next. A reader opening this file should immediately see what it defines. 3. **Supporting/subordinate types** (sub-structs, helper enums, serialization DTOs) go below the primary type, not above it. Ask: "Would a reader need to know this type exists before seeing the main type?" — if no, push it down. 4. **Type ordering for API types**: Request, then Response (success), then Error. 5. **`impl` blocks** after their type definitions. ### Ordering within an `impl` block 1. **Constructors** (`new`, `from_*`, `builder`) at the top. 2. **Public methods** next — these are the main entry points a reader cares about. 3. **Private helper methods** below public methods. - Among helpers: place "meaty" helpers (substantial logic, direct continuations of the public entry point) above "leaf" helpers (small formatters, simple lookups). - A method that calls another method in the same file should appear *above* the method it calls. This lets readers follow the call chain downward. ### Ordering within test modules Put test cases first, helpers last. A reader opening a test file should immediately see *what* is being tested before *how* the test machinery works. 1. **Imports** 2. **Constants** (test IDs, URLs, fixture data) — small context that tests reference 3. **Test functions** or **sub-modules** grouped by category 4. **Helper functions** (builders, pipeline runners, assertions) Group related tests into sub-modules (`mod pricing_tests { ... }`) when a category has 2+ tests. Don't create a sub-module for a single test. Keep nesting to two levels max (`mod tests { mod category { ... } }`). Shared helpers go in the parent module so sub-modules can reach them via `use super::*`. ## Naming - Handler functions: `{verb}_{noun}_handler` (e.g. `get_health_check_handler`, `login_handler`) - Error enums: `{Feature}Error` (e.g. `FalWebhookError`, `HealthCheckError`) - Request/response structs: `{Action}Request`, `{Action}Response`, `{Action}SuccessResponse` - Path params: `{Action}PathInfo` - Builder structs: `{Thing}Builder` with `set_` prefixed setters and a `build()` method ## Imports - Group imports: std, external crates, internal workspace crates, `crate::` imports - Prefer `use` imports over inline fully-qualified paths. Inline qualification is acceptable only for genuine one-off references where adding an import would be noise, or for types that collide with std prelude names (`Result`, `Option`, `Error`). If you reference a symbol more than once, always import it. - Prefer specific imports over wildcards, except in `api_doc.rs` and test modules - When two crates export a type with the same name, alias with a suffix describing the source crate: `use enums::...::CommonResolution as CommonResolutionEnum;` `use artcraft_router::...::CommonResolution as CommonResolutionRouter;` This avoids long fully-qualified paths in function signatures and bodies. ## MySQL - MySQL tables: primary key `id` columns must be `BIGINT(20) UNSIGNED`. Do not use signed IDs. - Always create tables with `ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin`. ## TypeScript / Frontend - TypeScript with React, Vite, Zustand, Three.js - Nx monorepo under `crates/frontend/` - Two spaces for indentation