# Step 3 — Project & Workspace Setup

Time to create the project. Rust's build tool, **Cargo**, handles compiling, dependencies, testing, and running — you'll use it for everything.

## Create the project

```bash
cargo new tasks-api
cd tasks-api
```

You get:

```
tasks-api/
├── Cargo.toml      # project manifest: name, version, dependencies
└── src/
    └── main.rs     # entry point
```

`Cargo.toml` is the heart of the project. It's where "what this backend can do" is declared.

## Add the backend dependencies

Open `Cargo.toml` and add the crates our Tasks API needs. These are the same core libraries iKanban's backend uses:

```toml
[package]
name = "tasks-api"
version = "0.1.0"
edition = "2024"

[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sqlx = { version = "0.8", features = [
    "runtime-tokio-rustls",
    "postgres",
    "macros",
    "chrono",
] }
chrono = { version = "0.4", features = ["serde"] }
```

A few things worth understanding, because they trip up newcomers:

- **`features = [...]`** — Rust crates ship optional pieces behind feature flags so you only compile what you use. `tokio`'s `"full"` pulls in the whole runtime; `sqlx`'s `"postgres"` enables the Postgres driver and `"macros"` enables the compile-time-checked query macros (Step 5).
- **`edition = "2024"`** — the language edition. Editions let Rust evolve without breaking old code; always start new projects on the latest.

Fetch and compile the dependency tree once:

```bash
cargo build
```

Cargo writes a `Cargo.lock` pinning exact versions. **Commit `Cargo.lock`** for an application — it makes builds reproducible.

## The command you'll use constantly

While developing, you rarely run the binary directly. Instead:

```bash
cargo check    # type-check WITHOUT producing a binary — fast, your inner loop
cargo run      # compile + run
cargo test     # run tests
cargo clippy   # lints that catch real bugs and non-idiomatic code
cargo fmt      # auto-format to the community style
```

`cargo check` is your best friend: it runs the full compiler front-end (so it catches every type and borrow error) but skips code generation, so it's fast. Run it after every change.

## When one crate isn't enough: workspaces

As a backend grows, you split it into multiple **crates** (compilation units) inside one **workspace**. This is exactly how iKanban's backend is organized — a top-level `Cargo.toml` lists members:

```toml
# Cargo.toml at the workspace root
[workspace]
resolver = "2"
members = [
    "crates/api",      # the Axum HTTP server
    "crates/db",       # database access + migrations
    "crates/domain",   # shared types and business logic
]
```

Why bother?

| Benefit | What it buys you |
|---|---|
| **Faster builds** | Change one crate, only that crate (and its dependents) recompile |
| **Clear boundaries** | `db` can't accidentally reach into HTTP concerns |
| **Reuse** | A CLI and the server can both depend on `domain` |

iKanban's real backend has a dozen crates (`remote` for the API, `db` for schema, `executors` for AI runners, and so on). You don't need that on day one — start with a single crate and split when a boundary becomes obvious.

> **Rule of thumb:** reach for a workspace when compile times hurt or when two parts of the system have genuinely different responsibilities. Splitting too early adds ceremony; splitting too late slows every build.

## Where we are

You have a compiling Cargo project with Axum, Tokio, Serde, and SQLx on hand, and you understand how it grows into a workspace. Next: **Step 4 — Your First Endpoint (Axum)**, where this project starts answering HTTP requests.
