# Contributing to AnimFX Store

Thank you for contributing! This guide covers code standards, workflow, and how to add features safely.

---

## 🛠 Development Setup

```bash
# 1. Fork & clone
git clone https://github.com/yourusername/svga-store.git
cd svga-store

# 2. Install deps (with dev tools)
composer install

# 3. Copy env & configure
cp .env.example .env
# Edit .env for local dev (SQLite, baseURL=http://localhost:8080/)

# 4. Fresh DB + seed
php spark migrate --all
php spark db:seed MainSeeder

# 5. Run dev server
php spark serve --port 8080
```

---

## 📝 Code Standards

### PHP (PSR-12 + CI4 Conventions)
- **Indent**: 4 spaces (no tabs)
- **Line length**: ≤ 120 chars
- **Strict types**: `declare(strict_types=1);` at top of every PHP file
- **Type hints**: Use wherever possible (PHP 8.1+ union types, `never`, `mixed`)
- **Naming**:
  - Classes: `PascalCase` (`PaymentGateway`)
  - Methods/Properties: `camelCase` (`paddleCheckoutUrl`)
  - Constants: `SCREAMING_SNAKE` (`PAYPAL = 'paypal'`)
  - Views: `snake_case` (`orders/checkout.php`)

### Lint Before Commit
```bash
# Check syntax on all changed PHP files
php -l $(git diff --name-only -- '*.php')

# Or all PHP files
find app -name "*.php" -exec php -l {} \;
```

### Database
- **Migrations**: One per logical change, timestamped filename (`YYYY-MM-DD-HHMMSS_Description.php`)
- **Never edit applied migrations** — create a new one
- **Seeders**: Only for reference/demo data, not production data
- **Foreign keys**: Use `$table->foreignKey()` in migrations

---

## 🌿 Git Workflow

### Branch Naming
| Type | Prefix | Example |
|------|--------|---------|
| Feature | `feat/` | `feat/paypal-refund-api` |
| Bugfix | `fix/` | `fix/webhook-idempotency` |
| Refactor | `refactor/` | `refactor/payment-gateway-interface` |
| Docs | `docs/` | `docs/deployment-guide` |
| Chore | `chore/` | `chore/update-dependencies` |

### Commit Messages (Conventional Commits)
```
<type>(<scope>): <short description>

<body - optional, wrap at 72 chars>

<footer - optional: Breaking changes, issue refs>
```

**Types:** `feat`, `fix`, `refactor`, `docs`, `style`, `test`, `chore`, `perf`, `ci`, `build`

**Examples:**
```
feat(payments): add PayPal capture validation helper

- Extract amount/currency/order validation to confirmPaypalCapture()
- Used by both return URL and webhook handler
- Adds idempotency check on payment_txn_id

Closes #42
```

```
fix(webhook): prevent replay attack on Binance webhook

- Add timestamp freshness check (±5 min)
- Reject duplicate transmission_id

Fixes #57
```

### Pull Request Checklist
- [ ] **Lint passes** (`php -l` on all changed files)
- [ ] **Tests pass** (run relevant manual E2E scripts)
- [ ] **Migrations included** if schema changes
- [ ] **Seeder updated** if new reference data needed
- [ ] **Docs updated** (README, DEPLOYMENT, inline PHPDoc)
- [ ] **No secrets** in code (check `.env`, API keys, passwords)
- [ ] **Breaking changes** documented in PR description

---

## 🧪 Testing

### Manual E2E Tests (Required for Payment Changes)
```bash
# Start dev server
php spark serve --port 8080

# Run tests
php tests/manual/_paddle_e2e_test.php
php tests/manual/_paypal_e2e_test.php
```

**When to run:**
- Any change to `app/Libraries/PaymentGateway.php`
- Any change to `app/Controllers/Payment.php`
- Any change to `app/Controllers/Orders.php` (checkout/pay flow)
- New payment gateway added

### Adding New Payment Gateway
1. Add constant to `PaymentGateway` (`const NEW_GATEWAY = 'new_gateway'`)
2. Implement `newGatewayEnabled()`, `newGatewayCheckoutUrl()`, `handleNewGatewayWebhook()`
3. Add `confirmNewGatewayCapture()` for amount/currency/idempotency validation
4. Add webhook route in `Routes.php`
5. Add admin settings fields (credentials, enable toggle, sandbox toggle)
6. Add view option in `orders/checkout.php` + `orders/detail.php`
7. Add seeder defaults in `MainSeeder.php`
8. **Write E2E test** in `tests/manual/_newgateway_e2e_test.php` (copy PayPal test as template)

---

## 🏗 Architecture Guidelines

### Controllers
- **Thin** — delegate to Models/Libraries
- **Validation** in controller (`$this->validate()`) or Form Validation config
- **Responses**: `redirect()->with()`, `view()`, `response()->setJSON()`

### Models
- **Fat** — business logic, queries, relationships
- Use `$allowedFields`, `$validationRules`, `$useTimestamps`
- Scope methods: `getActive()`, `getByUser($id)`

### Libraries (Services)
- **Stateless** — no `$this->property` that persists across requests
- **Single responsibility** — `PaymentGateway` handles all provider logic
- **Inject dependencies** via constructor or method params (not `service()` inside)

### Views
- **No logic** — only `if/foreach/echo`, no DB queries
- Use `esc()` on all output
- Reuse partials via `view_cell()` or `include`

### Routes
- **Group by prefix** (`$routes->group('admin', ['filter' => 'admin'], ...)`)
- **Named routes** for complex URLs: `$routes->get('orders/(:segment)', 'Orders::detail/$1', ['as' => 'order.detail'])`

---

## 🔐 Security Rules

1. **Never commit secrets** — `.env`, API keys, passwords, webhook secrets
2. **Validate all input** — `$this->validate()`, `$allowedFields` in models
3. **Escape all output** — `esc()` in views, `htmlspecialchars()` in controllers
4. **CSRF on all forms** — `<?= csrf_field() ?>` + `app.CSRFProtection = true`
5. **Admin routes** — protected by `AdminFilter` (checks `session('user_role') === 'admin'`)
6. **File uploads** — validate MIME, size, extension; store in `writable/uploads/` (non-public)
7. **SQL injection** — use Query Builder / Model methods, never raw concatenation

---

## 📦 Dependency Management

### Adding Composer Package
```bash
composer require vendor/package
# Commit composer.json + composer.lock
```

### Updating
```bash
composer update vendor/package
# Test thoroughly, commit lock file
```

### PHP Version
- **Minimum**: 8.1 (per `composer.json`)
- **Target**: 8.3 (current LTS)
- Use `match` expressions, `readonly` properties, `#[Attribute]`, union types

---

## 📋 Code Review Checklist

| Area | What to Check |
|------|---------------|
| **Correctness** | Logic matches requirements, edge cases handled |
| **Security** | Input validation, output escaping, auth checks |
| **Performance** | N+1 queries, missing indexes, heavy operations in loops |
| **Maintainability** | Clear naming, small methods, comments for complex logic |
| **Tests** | Manual E2E for payments, migration + seeder if schema change |
| **Docs** | PHPDoc on public methods, README/DEPLOYMENT updated |
| **Breaking Changes** | Migration provided, config changes documented |

---

## 🐛 Reporting Issues

Use GitHub Issues with:
- **Title**: `[Area] Short description` (e.g., `[Payments] Webhook fails on duplicate`)
- **Environment**: PHP version, CI4 version, hosting type
- **Steps to reproduce**: Minimal steps
- **Expected vs Actual**: What should happen vs what happens
- **Logs**: Relevant `writable/logs/` entries (redact secrets)
- **Screenshots**: If UI-related

---

## 📄 License

By contributing, you agree your contributions will be licensed under the **MIT License** (same as project).

---

*Happy coding! 🚀*