# DEVELOP.md — Development Rules & Tracking

## Quick Start

```bash
# Prerequisites
rustup show            # Rust 1.80+

# Run locally (DoH on :8800, DNS on :53530)
cargo run

# Run with custom config
cargo run -- --config path/to/config.toml

# Run tests
cargo test

# Lint & format
cargo clippy -- -D warnings
cargo fmt --check
```

## Development Rules

### Code Quality

1. **No warnings.** All code must compile with zero warnings. CI treats warnings as errors (`-D warnings`).
2. **Format before commit.** Run `cargo fmt` — CI checks formatting.
3. **Clippy clean.** Run `cargo clippy -- -D warnings` — CI checks lints.
4. **Tests required.** Every new module/function must have unit tests. Public API changes require integration tests.
5. **Doc comments.** All public items (`pub fn`, `pub struct`, `pub enum`) must have `///` doc comments.

### Git Workflow

1. **Branch naming**: `<type>/<short-description>`
   - `feat/dns-cache`, `fix/ttl-overflow`, `docs/readme`, `chore/ci-update`
2. **Commit messages**: Conventional Commits format
   - `feat: add DNS response cache`
   - `fix: handle truncated UDP responses`
   - `docs: update plan.md`
3. **PR required.** All changes go through a pull request. No direct pushes to `main`.
4. **Squash merge.** PRs are squash-merged into `main`.
5. **CI must pass.** Lint, test, and build must succeed before merge.

### Architecture Rules

1. **No panics in production code.** Use `Result<T, E>` everywhere. `unwrap()` only in tests.
2. **Structured errors.** Define error types per module using `thiserror`. Use `anyhow` only in `main.rs`.
3. **Async everywhere.** All I/O is async (Tokio). No blocking calls in async context.
4. **Config-driven.** No hardcoded values. All tunables come from config file or env vars.
5. **Dependency injection.** Accept traits, not concrete types. Makes testing easy.

### Testing Rules

1. **Unit tests** in the same file (`#[cfg(test)] mod tests { ... }`).
2. **Integration tests** in `tests/` directory.
3. **Test naming**: `test_<what>_<condition>_<expected>` — e.g., `test_cache_expired_entry_returns_miss`.
4. **No external dependencies in unit tests.** Mock upstream resolvers.
5. **Integration tests** may spin up the full server on a random port.

### Security Rules

1. **No secrets in code.** Use env vars or config files (gitignored).
2. **Validate all input.** DNS queries from the network are untrusted — validate lengths, offsets, labels.
3. **Timeouts on all upstream calls.** Never hang indefinitely.
4. **Rate limiting.** Protect against abuse from a single IP.
5. **Dependency audit.** Run `cargo audit` in CI.

### Commit Checklist

Before pushing, verify:

- [ ] `cargo fmt --check` passes
- [ ] `cargo clippy -- -D warnings` passes
- [ ] `cargo test` passes
- [ ] New code has tests
- [ ] Public items have doc comments
- [ ] No `unwrap()` outside of tests
- [ ] Config values are externalized (not hardcoded)

## References

- [Intra Comparison](docs/intra-comparison.md) — Architectural comparison
  with Jigsaw's Intra, explaining why DNS forwarding alone can't bypass
  censorship and what's needed (TLS splitting, TUN interception, etc.)

## Milestone Tracking

See [docs/plan.md](docs/plan.md) for the full project plan and milestone checklist.

| Milestone | Status |
|-----------|--------|
| M1 — Core Forwarding | ✅ Done |
| M2 — Multiple Upstreams & Config | ✅ Done |
| M3 — Local DNS Listener | ✅ Done (UDP/TCP integration tests pending) |
| M4 — Caching | 🔲 Not started |
| M5 — Observability | 🔲 Not started |
| M6 — Blocking & Filtering | 🔲 Not started |
| M7 — Production Hardening | 🔲 Not started |
| M8 — Censorship Resistance | 🔲 Not started |

## Useful Commands

```bash
# Build release binary
cargo build --release

# Run with specific log level
RUST_LOG=debug cargo run

# Generate and open docs
cargo doc --open

# Dependency audit
cargo install cargo-audit
cargo audit

# Watch tests
cargo watch -x test
```
