# Contributing to RankWiz AI

## Local Setup

```bash
# 1. Clone and install dependencies
git clone <repo>
cd rankwiz
composer install
npm install

# 2. Configure environment
cp .env.example .env
php artisan key:generate

# 3. Create the SQLite database and run migrations
touch database/database.sqlite
php artisan migrate --seed   # seeds test user + local demo data

# 4. Build frontend assets
npm run build

# 5. Start the dev server (Laravel + queue worker + Vite, concurrently)
composer run dev
```

**Prerequisites:** PHP 8.4+, Node 22+, Composer 2.x

---

## Running Tests

```bash
# PHP — always use parallel mode (~60s vs ~30min serial)
./vendor/bin/pest --parallel --processes=4

# Run a single test file
./vendor/bin/pest tests/Feature/SomeTest.php

# Contract tests only (Inertia page/props contracts)
./vendor/bin/pest --testsuite=Contracts

# Frontend
npx vitest run

# Frontend watch mode
npm run test:watch
```

---

## Pre-flight Checklist

Run all quality gates before opening a PR:

```bash
# PHP tests
./vendor/bin/pest --parallel --processes=4

# Frontend build
npm run build

# Lint (0 warnings enforced)
npm run lint

# TypeScript type-check
npm run typecheck

# PHP static analysis
composer analyze

# Or run PHP-only quality gate (tests + Pint + PHPStan)
composer check:php

# Security audits
composer audit
npm audit --audit-level=critical

# Contract tests (Inertia page/props)
./vendor/bin/pest --testsuite=Contracts
```

After any route changes: `php artisan ziggy:generate`

---

## Code Style

**PHP:** Laravel Pint (PSR-12 based). Run `composer lint` or `./vendor/bin/pint` to auto-format.

**TypeScript/React:** ESLint enforces zero warnings (`--max-warnings=0`). Run `npm run lint:fix` to auto-fix. No `any` types — use `Record<string, unknown>`, `unknown`, or proper interfaces.

---

## Branch Naming

```
feat/short-description      # New feature
fix/short-description       # Bug fix
chore/short-description     # Tooling, deps, config
refactor/short-description  # Refactoring
```

---

## Commit Conventions

Use clear, imperative commit messages:

```
Add keyword opportunity detection to analysis engine
Fix eager loading violation in RecommendationController
Update DataForSEO client to handle rate limit retries
```

---

## Pull Request Process

1. Branch from `main`
2. Run the full pre-flight checklist above
3. Open a PR — keep it focused on one concern
4. PR description should explain **why** the change was made, not just what changed
5. All CI checks must pass before merge

---

## Architecture Notes

See `CLAUDE.md` for the full architecture overview, service layer patterns, and critical gotchas. Key points for contributors:

- **No lazy loading** — always eager-load relationships before accessing them
- **External API calls in Jobs only** — never in the request lifecycle
- **Form Requests for all mutation endpoints** — never validate in controllers
- **Every new model needs a factory** in `database/factories/`
- **Inertia pages must exist before the controller renders them** — contract tests enforce this
