# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Teams Phone CLI - A Python CLI tool for managing Microsoft Teams Phone configurations via Microsoft Graph API. Uses certificate-based authentication with Microsoft Entra ID.

## Commands

```bash
# Install dependencies (uses uv package manager)
uv pip install -e ".[dev]"

# Run the CLI
python -m teams_phone

# Testing
uv run pytest tests/                    # All tests
uv run pytest tests/ -m unit            # Unit tests only
uv run pytest tests/ -m integration     # Integration tests (requires API access)
uv run pytest tests/ -m contract        # Contract validation tests
uv run pytest tests/unit/test_exceptions.py -v  # Single test file
uv run pytest tests/unit/test_graph_client.py::TestGraphClient::test_get_success -v  # Single test

# Code quality
ruff check src/ tests/           # Lint
ruff format src/ tests/          # Format
mypy src/ tests/                 # Type check (strict mode)
pre-commit run --all-files       # Run all hooks
```

## Architecture

**Layered Monolith:**
```
src/teams_phone/
├── cli/            # Typer commands (user interface)
├── services/       # Business logic (UserService, NumberService, PolicyService, etc.)
├── infrastructure/ # Graph API client, cache manager, config manager
├── models/         # Pydantic models (strict mode)
├── constants.py    # API URLs, exit codes, defaults
├── exceptions.py   # Exception hierarchy with exit codes
└── utils.py        # Phone number normalization
```

**Key Patterns:**
- Services abstract Graph API + CSV cache access (repository pattern)
- Graph assign/unassign operations return 202 and require polling
- CSV cache for locations/policies (Graph API limitations) - exported via PowerShell script
- Exponential backoff retry (3 retries) for Graph API throttling (429, 503)
- Pydantic models use `extra="forbid"` to fail-fast on unexpected API fields (contract validation)
- GraphClient is an async context manager: `async with GraphClient(...) as client:`

**Exception Hierarchy:** All inherit from `TeamsPhoneError` with specific exit codes (2-8) for auth, authorization, not-found, validation, rate-limit, config, and contract errors.

## Task Management

This project uses TaskMaster for phased implementation tracking. Tasks are in `.taskmaster/tasks/`.

```bash
# Use these Claude skills for task workflow
/task-recon [task-id]    # Deep reconnaissance before implementation
/task-implement          # Execute implementation with context
```

## Documentation

- `.taskmaster/docs/architecture/` - Architecture decisions and component design
- `.taskmaster/docs/cli-specification/` - CLI command specifications
- `.taskmaster/docs/graph-api-contracts/` - Graph API endpoint contracts
- `scripts/README.md` - PowerShell CSV export setup and troubleshooting

## Graph API Notes

- Uses beta endpoint (`graph.microsoft.com/beta`) for Teams Phone operations
- Requires 8 application permissions + Teams Administrator role
- Certificate-based auth via MSAL
- Async operations (number assignment) return 202 - must poll for completion

## Testing Notes

- Unit tests mock GraphClient with `respx` for HTTP-level mocking
- Contract tests validate real API responses against Pydantic models (requires API access)
- Tests use `asyncio_mode = "strict"` - async tests must be explicitly marked with `@pytest.mark.asyncio`
