# Common Development Workflows

Standard workflows for common development tasks in the Custom PHP Framework.

## Adding a New Feature

### Step 1: Planning & Design

**Define the Feature**:
```bash
# Document feature requirements
# - What problem does it solve?
# - What are the acceptance criteria?
# - What are the security implications?
# - What is the performance impact?
```

**Design Decision Checklist**:
- [ ] Does this fit framework architecture?
- [ ] Are there existing patterns to follow?
- [ ] What Value Objects are needed?
- [ ] What events should be dispatched?
- [ ] What tests are required?

---

### Step 2: Create Domain Model

**Create Value Objects**:
```php
// src/Domain/Orders/ValueObjects/OrderId.php
namespace App\Domain\Orders\ValueObjects;

final readonly class OrderId
{
    public function __construct(public string $value)
    {
        if (empty($value)) {
            throw new \InvalidArgumentException('OrderId cannot be empty');
        }
    }

    public static function generate(): self
    {
        return new self(\Symfony\Component\Uid\Ulid::generate());
    }

    public function equals(self $other): bool
    {
        return $this->value === $other->value;
    }
}
```

**Create Domain Entity**:

```php
// src/Domain/Orders/Entities/Order.php
namespace App\Domain\Orders\Entities;

use App\Domain\Orders\ValueObjects\{OrderId, OrderStatus};
use App\Framework\Core\ValueObjects\Timestamp;

final readonly class Order
{
    public function __construct(
        public OrderId $id,
        public UserId $userId,
        public OrderStatus $status,
        public Money $total,
        public Timestamp $createdAt
    ) {}

    public static function create(UserId $userId, Money $total): self
    {
        return new self(
            id: OrderId::generate(),
            userId: $userId,
            status: OrderStatus::PENDING,
            total: $total,
            createdAt: Timestamp::now()
        );
    }

    public function confirm(): self
    {
        if (!$this->status->equals(OrderStatus::PENDING)) {
            throw new \DomainException('Only pending orders can be confirmed');
        }

        return new self(
            id: $this->id,
            userId: $this->userId,
            status: OrderStatus::CONFIRMED,
            total: $this->total,
            createdAt: $this->createdAt
        );
    }
}
```

**Regenerate Autoloader**:
```bash
composer reload
# Or in Docker
make reload
```

---

### Step 3: Create Service Layer

**Create Service**:
```php
// src/Domain/Orders/Services/OrderService.php
namespace App\Domain\Orders\Services;

use App\Domain\Orders\{Entities\Order, Repositories\OrderRepository};
use App\Framework\Events\EventDispatcher;
use App\Domain\Orders\Events\OrderCreatedEvent;

final readonly class OrderService
{
    public function __construct(
        private readonly OrderRepository $repository,
        private readonly EventDispatcher $events
    ) {}

    public function createOrder(UserId $userId, Money $total): Order
    {
        // Create order
        $order = Order::create($userId, $total);

        // Persist
        $this->repository->save($order);

        // Dispatch event
        $this->events->dispatch(new OrderCreatedEvent($order));

        return $order;
    }

    public function confirmOrder(OrderId $orderId): Order
    {
        // Find order
        $order = $this->repository->findById($orderId);

        if ($order === null) {
            throw new OrderNotFoundException($orderId);
        }

        // Confirm
        $confirmedOrder = $order->confirm();

        // Update
        $this->repository->save($confirmedOrder);

        // Dispatch event
        $this->events->dispatch(new OrderConfirmedEvent($confirmedOrder));

        return $confirmedOrder;
    }
}
```

**Register Service in Container**:
```php
// src/Domain/Orders/OrdersInitializer.php
namespace App\Domain\Orders;

use App\Framework\DI\Container;
use App\Framework\Attributes\Initializer;

final readonly class OrdersInitializer
{
    #[Initializer]
    public function initialize(Container $container): void
    {
        // Register repository
        $container->singleton(
            OrderRepository::class,
            new DatabaseOrderRepository(
                $container->get(Connection::class)
            )
        );

        // Register service
        $container->singleton(
            OrderService::class,
            fn() => new OrderService(
                $container->get(OrderRepository::class),
                $container->get(EventDispatcher::class)
            )
        );
    }
}
```

**Regenerate Autoloader**:
```bash
composer reload
```

---

### Step 4: Create API Endpoint

**Create Controller**:
```php
// src/Application/Api/OrderController.php
namespace App\Application\Api;

use App\Framework\Attributes\Route;
use App\Framework\Http\{Method, JsonResult, Request};
use App\Domain\Orders\Services\OrderService;

final readonly class OrderController
{
    public function __construct(
        private readonly OrderService $orderService
    ) {}

    #[Route(path: '/api/orders', method: Method::POST)]
    #[Auth(strategy: 'session')]
    public function createOrder(CreateOrderRequest $request): JsonResult
    {
        $order = $this->orderService->createOrder(
            userId: $request->userId,
            total: $request->total
        );

        return new JsonResult([
            'order_id' => $order->id->value,
            'status' => $order->status->value,
            'total' => $order->total->toArray()
        ], status: Status::CREATED);
    }

    #[Route(path: '/api/orders/{orderId}/confirm', method: Method::POST)]
    #[Auth(strategy: 'session')]
    public function confirmOrder(string $orderId): JsonResult
    {
        $order = $this->orderService->confirmOrder(
            new OrderId($orderId)
        );

        return new JsonResult([
            'order_id' => $order->id->value,
            'status' => $order->status->value
        ]);
    }
}
```

**Create Request Object**:
```php
// src/Application/Api/Requests/CreateOrderRequest.php
namespace App\Application\Api\Requests;

use App\Framework\Http\{Request as HttpRequest, ControllerRequest};

final readonly class CreateOrderRequest implements ControllerRequest
{
    public function __construct(
        public UserId $userId,
        public Money $total
    ) {}

    public static function fromHttpRequest(HttpRequest $request): self
    {
        $data = $request->parsedBody->toArray();

        return new self(
            userId: new UserId($data['user_id'] ?? ''),
            total: Money::fromCents((int) ($data['total_cents'] ?? 0))
        );
    }
}
```

**Verify Route Registration**:
```bash
docker exec php php console.php routes:list | grep orders
```

---

### Step 5: Create Database Migration

```bash
# Generate migration
docker exec php php console.php make:migration CreateOrdersTable Domain/Orders

# Edit migration
# src/Domain/Orders/Database/Migrations/2025_01_28_120000_CreateOrdersTable.php
```

**Migration Implementation**:
```php
namespace App\Domain\Orders\Database\Migrations;

use App\Framework\Database\Migration\{Migration, SafelyReversible};
use App\Framework\Database\Schema\{Blueprint, Schema};

final readonly class CreateOrdersTable implements Migration, SafelyReversible
{
    public function up(Schema $schema): void
    {
        $schema->create('orders', function (Blueprint $table) {
            $table->string('ulid', 26)->primary();
            $table->string('user_id', 26);
            $table->string('status', 20);
            $table->integer('total_cents');
            $table->string('currency', 3)->default('EUR');
            $table->timestamps();

            // Indexes
            $table->index('user_id');
            $table->index('status');
            $table->index('created_at');

            // Foreign key
            $table->foreign('user_id')
                ->references('ulid')
                ->on('users')
                ->onDelete(ForeignKeyAction::CASCADE);
        });
    }

    public function down(Schema $schema): void
    {
        $schema->dropIfExists('orders');
    }

    public function getVersion(): MigrationVersion
    {
        return MigrationVersion::fromString('2025_01_28_120000');
    }

    public function getDescription(): string
    {
        return 'Create orders table';
    }
}
```

**Run Migration**:
```bash
docker exec php php console.php db:migrate
```

---

### Step 6: Write Tests

**Unit Test - Domain Logic**:
```php
// tests/Unit/Domain/Orders/Entities/OrderTest.php
use App\Domain\Orders\Entities\Order;
use App\Domain\Orders\ValueObjects\{OrderId, OrderStatus};

describe('Order Entity', function () {
    it('creates order with pending status', function () {
        $order = Order::create(
            userId: new UserId('user-123'),
            total: Money::fromEuros(99.99)
        );

        expect($order->status)->toEqual(OrderStatus::PENDING);
        expect($order->total->toEuros())->toBe(99.99);
    });

    it('confirms pending order', function () {
        $order = Order::create(
            userId: new UserId('user-123'),
            total: Money::fromEuros(99.99)
        );

        $confirmed = $order->confirm();

        expect($confirmed->status)->toEqual(OrderStatus::CONFIRMED);
    });

    it('throws exception when confirming non-pending order', function () {
        $order = Order::create(
            userId: new UserId('user-123'),
            total: Money::fromEuros(99.99)
        )->confirm();

        $order->confirm(); // Should throw
    })->throws(\DomainException::class);
});
```

**Integration Test - API Endpoint**:
```php
// tests/Feature/Api/OrderControllerTest.php
use App\Application\Api\OrderController;

describe('Order API', function () {
    it('creates order via API', function () {
        $response = $this->post('/api/orders', [
            'user_id' => 'user-123',
            'total_cents' => 9999
        ]);

        expect($response->status)->toBe(Status::CREATED);
        expect($response->json('order_id'))->not->toBeNull();
        expect($response->json('status'))->toBe('pending');
    });

    it('confirms order via API', function () {
        // Create order first
        $createResponse = $this->post('/api/orders', [
            'user_id' => 'user-123',
            'total_cents' => 9999
        ]);

        $orderId = $createResponse->json('order_id');

        // Confirm order
        $confirmResponse = $this->post("/api/orders/{$orderId}/confirm");

        expect($confirmResponse->status)->toBe(Status::OK);
        expect($confirmResponse->json('status'))->toBe('confirmed');
    });
});
```

**Run Tests**:
```bash
./vendor/bin/pest
```

---

### Step 7: Documentation

**Update API Documentation**:
```markdown
## Create Order

**Endpoint**: `POST /api/orders`
**Auth**: Session required

**Request Body**:
```json
{
  "user_id": "01HQXYZ...",
  "total_cents": 9999
}
```

**Response** (201 Created):
```json
{
  "order_id": "01HQABC...",
  "status": "pending",
  "total": {
    "cents": 9999,
    "currency": "EUR"
  }
}
```
```

---

### Step 8: Code Review Checklist

- [ ] Value Objects for all domain concepts
- [ ] Immutable entities (readonly classes)
- [ ] Events dispatched for important actions
- [ ] Exception handling implemented
- [ ] Tests cover happy path and edge cases
- [ ] Migration includes indexes and foreign keys
- [ ] API returns appropriate status codes
- [ ] Security: Authentication/Authorization applied
- [ ] Performance: N+1 queries avoided
- [ ] Documentation updated

---

## Implementing an API Endpoint

### Quick API Endpoint Guide

**1. Create Controller Method**:
```php
#[Route(path: '/api/resource', method: Method::GET)]
public function getResource(string $id): JsonResult
{
    $resource = $this->service->find($id);

    return new JsonResult($resource->toArray());
}
```

**2. Add Authentication**:
```php
#[Route(path: '/api/resource', method: Method::POST)]
#[Auth(strategy: 'session', roles: ['admin'])]
public function createResource(CreateRequest $request): JsonResult
{
    // Only authenticated admins can access
}
```

**3. Create Request Object**:
```php
final readonly class CreateRequest implements ControllerRequest
{
    public function __construct(
        public string $name,
        public Email $email
    ) {}

    public static function fromHttpRequest(HttpRequest $request): self
    {
        $data = $request->parsedBody->toArray();

        return new self(
            name: trim($data['name'] ?? ''),
            email: new Email($data['email'] ?? '')
        );
    }
}
```

**4. Handle Errors**:
```php
try {
    $resource = $this->service->create($request);

    return new JsonResult(
        $resource->toArray(),
        status: Status::CREATED
    );
} catch (ValidationException $e) {
    return new JsonResult(
        ['errors' => $e->getErrors()],
        status: Status::UNPROCESSABLE_ENTITY
    );
} catch (\Exception $e) {
    Logger::error('[API] Unexpected error', ['exception' => $e]);

    return new JsonResult(
        ['error' => 'Internal server error'],
        status: Status::INTERNAL_SERVER_ERROR
    );
}
```

**5. Test Endpoint**:
```bash
# Manual test
curl -X POST https://localhost/api/resource \
  -H "Content-Type: application/json" \
  -H "User-Agent: Mozilla/5.0" \
  -d '{"name":"Test","email":"test@example.com"}'

# Automated test
./vendor/bin/pest --filter CreateResourceTest
```

---

### REST API Best Practices

**HTTP Methods**:
- `GET` - Retrieve resources (idempotent)
- `POST` - Create new resources
- `PUT` - Update entire resource (idempotent)
- `PATCH` - Partial update
- `DELETE` - Remove resource (idempotent)

**Status Codes**:
- `200 OK` - Successful GET/PUT/PATCH
- `201 Created` - Successful POST with resource created
- `204 No Content` - Successful DELETE
- `400 Bad Request` - Invalid request format
- `401 Unauthorized` - Authentication required
- `403 Forbidden` - Insufficient permissions
- `404 Not Found` - Resource doesn't exist
- `422 Unprocessable Entity` - Validation errors
- `429 Too Many Requests` - Rate limit exceeded
- `500 Internal Server Error` - Server-side error

**Response Format**:
```php
// Success response
return new JsonResult([
    'data' => $resource->toArray(),
    'meta' => [
        'timestamp' => time(),
        'version' => '2.0'
    ]
]);

// Error response
return new JsonResult([
    'error' => [
        'code' => 'VALIDATION_ERROR',
        'message' => 'Validation failed',
        'details' => [
            'email' => ['Email format is invalid']
        ]
    ]
], status: Status::UNPROCESSABLE_ENTITY);
```

---

## Bug Fix Workflow

### Step 1: Reproduce the Bug

**Create Reproduction Test**:
```php
// tests/Unit/Bug123Test.php
describe('Bug #123: Orders not updating status', function () {
    it('reproduces the bug', function () {
        $order = Order::create(/* ... */);

        $order->confirm();

        // This should update status but doesn't
        expect($order->status)->toBe(OrderStatus::CONFIRMED);
    })->skip('Bug reproduction - currently failing');
});
```

**Run Test to Confirm Failure**:
```bash
./vendor/bin/pest --filter Bug123Test
```

---

### Step 2: Debug and Identify Root Cause

**Enable Debug Logging**:
```php
// Add logging to suspected code
Logger::debug('[OrderService] Confirming order', [
    'order_id' => $order->id->value,
    'current_status' => $order->status->value
]);

$confirmedOrder = $order->confirm();

Logger::debug('[OrderService] Order confirmed', [
    'order_id' => $confirmedOrder->id->value,
    'new_status' => $confirmedOrder->status->value
]);
```

**Check Database Queries**:
```bash
# Enable query logging
docker exec php php -r "
\$logger = new App\Framework\Database\QueryLogger();
// Run problematic code
"
```

**Use MCP Server for Analysis**:
```bash
# Analyze routes
docker exec php php console.php mcp:analyze routes

# Analyze container bindings
docker exec php php console.php mcp:analyze container
```

---

### Step 3: Fix the Bug

**Identify and Fix**:
```php
// ❌ Bug: Not saving updated order
public function confirmOrder(OrderId $orderId): Order
{
    $order = $this->repository->findById($orderId);
    $confirmedOrder = $order->confirm();

    // Missing: $this->repository->save($confirmedOrder);

    return $confirmedOrder;
}

// ✅ Fix: Save updated order
public function confirmOrder(OrderId $orderId): Order
{
    $order = $this->repository->findById($orderId);
    $confirmedOrder = $order->confirm();

    // Save updated order
    $this->repository->save($confirmedOrder);

    return $confirmedOrder;
}
```

---

### Step 4: Update Tests

**Enable and Verify Test**:
```php
describe('Bug #123: Orders not updating status', function () {
    it('confirms order and persists status', function () {
        $order = Order::create(/* ... */);

        $confirmedOrder = $this->orderService->confirmOrder($order->id);

        // Verify status is updated
        expect($confirmedOrder->status)->toBe(OrderStatus::CONFIRMED);

        // Verify persistence
        $retrieved = $this->repository->findById($order->id);
        expect($retrieved->status)->toBe(OrderStatus::CONFIRMED);
    });
});
```

**Run All Tests**:
```bash
./vendor/bin/pest
```

---

### Step 5: Regression Prevention

**Add Integration Test**:
```php
it('persists order status changes', function () {
    $order = Order::create(/* ... */);
    $this->repository->save($order);

    // Confirm order
    $confirmed = $this->orderService->confirmOrder($order->id);

    // Retrieve from database
    $fromDb = $this->repository->findById($order->id);

    expect($fromDb->status)->toBe(OrderStatus::CONFIRMED);
});
```

---

### Step 6: Documentation

**Update Changelog**:
```markdown
## [2.1.1] - 2025-01-28

### Fixed
- **Orders**: Fixed bug where order status was not persisted after confirmation (#123)
  - Added missing repository save call in OrderService::confirmOrder()
  - Added regression test to prevent future occurrence
```

---

## Database Migration Workflow

### Creating a Migration

```bash
# Generate migration file
docker exec php php console.php make:migration AddEmailVerifiedColumn Users

# Migration file created at:
# src/Domain/Users/Database/Migrations/2025_01_28_143000_AddEmailVerifiedColumn.php
```

**Implement Migration**:
```php
namespace App\Domain\Users\Database\Migrations;

use App\Framework\Database\Migration\{Migration, SafelyReversible};
use App\Framework\Database\Schema\{Blueprint, Schema};

final readonly class AddEmailVerifiedColumn implements Migration, SafelyReversible
{
    public function up(Schema $schema): void
    {
        $schema->table('users', function (Blueprint $table) {
            // Add column
            $table->boolean('email_verified')->default(false);
            $table->timestamp('email_verified_at')->nullable();

            // Add index for querying verified users
            $table->index('email_verified');
        });
    }

    public function down(Schema $schema): void
    {
        $schema->table('users', function (Blueprint $table) {
            // Drop in reverse order
            $table->dropIndex('email_verified');
            $table->dropColumn('email_verified_at', 'email_verified');
        });
    }

    public function getVersion(): MigrationVersion
    {
        return MigrationVersion::fromString('2025_01_28_143000');
    }

    public function getDescription(): string
    {
        return 'Add email verification columns to users table';
    }
}
```

---

### Running Migrations

```bash
# Check migration status
docker exec php php console.php db:status

# Run pending migrations
docker exec php php console.php db:migrate

# Rollback last migration
docker exec php php console.php db:rollback

# Rollback multiple steps
docker exec php php console.php db:rollback 3
```

---

### Migration Best Practices

**Safe Rollbacks**:
- Only implement `SafelyReversible` if rollback is data-safe
- Document why a migration is not reversible if omitting `down()`

**Column Modifications**:
```php
// ✅ Safe: Adding nullable column
$table->string('new_field')->nullable();

// ⚠️ Requires data migration: Adding required column
$table->string('required_field'); // Existing rows will fail!

// ✅ Better: Add nullable, migrate data, then make required
// Migration 1: Add nullable
$table->string('required_field')->nullable();

// Migration 2 (data): Populate existing rows
// Migration 3 (schema): Make required
$table->string('required_field')->nullable(false)->change();
```

**Performance Considerations**:
```php
// ⚠️ Slow: Adding index to large table
$table->index('email'); // Blocks table on large datasets

// ✅ Better: Use online algorithm (MySQL 5.7+)
$connection->statement(
    'ALTER TABLE users ADD INDEX idx_email (email) ALGORITHM=INPLACE, LOCK=NONE'
);
```

---

## Refactoring Workflow

### Safe Refactoring Process

**1. Ensure Test Coverage**:
```bash
# Run tests before refactoring
./vendor/bin/pest --coverage

# Minimum 80% coverage for critical code paths
```

**2. Make Small, Incremental Changes**:
```php
// ❌ Bad: Large refactoring in one step
// Refactor entire service layer at once

// ✅ Good: Incremental refactoring
// Step 1: Extract method
// Step 2: Move to new class
// Step 3: Update references
// Run tests after each step
```

**3. Extract Method**:
```php
// Before
public function processOrder(Order $order): void
{
    // Validate payment
    if ($order->total->cents < 100) {
        throw new MinimumOrderException();
    }

    // Process payment
    $this->gateway->charge($order->total);

    // Send confirmation
    $this->mailer->send($order->user->email, 'Order confirmed');

    // Update inventory
    foreach ($order->items as $item) {
        $this->inventory->reduce($item->productId, $item->quantity);
    }
}

// After
public function processOrder(Order $order): void
{
    $this->validateOrder($order);
    $this->chargePayment($order);
    $this->sendConfirmation($order);
    $this->updateInventory($order);
}

private function validateOrder(Order $order): void
{
    if ($order->total->cents < 100) {
        throw new MinimumOrderException();
    }
}

private function chargePayment(Order $order): void
{
    $this->gateway->charge($order->total);
}

// ... etc
```

**4. Extract Class**:
```php
// Before: God class with too many responsibilities
final readonly class OrderService
{
    public function processOrder(Order $order): void { /* ... */ }
    public function chargePayment(Order $order): void { /* ... */ }
    public function sendConfirmation(Order $order): void { /* ... */ }
    public function updateInventory(Order $order): void { /* ... */ }
}

// After: Separate concerns
final readonly class OrderService
{
    public function __construct(
        private readonly OrderProcessor $processor,
        private readonly PaymentHandler $payment,
        private readonly NotificationService $notifications,
        private readonly InventoryUpdater $inventory
    ) {}

    public function processOrder(Order $order): void
    {
        $this->processor->validate($order);
        $this->payment->charge($order);
        $this->notifications->sendConfirmation($order);
        $this->inventory->update($order);
    }
}
```

**5. Run Tests After Each Step**:
```bash
./vendor/bin/pest
```

---

### Refactoring Patterns

**Replace Primitive with Value Object**:
```php
// Before
final readonly class User
{
    public function __construct(
        public string $id,
        public string $email,
        public string $name
    ) {}
}

// After
final readonly class User
{
    public function __construct(
        public UserId $id,
        public Email $email,
        public UserName $name
    ) {}
}
```

**Replace Magic Numbers**:
```php
// Before
if ($user->age >= 18) {
    // Can vote
}

// After
final readonly class VotingAge
{
    public const MINIMUM = 18;
}

if ($user->age >= VotingAge::MINIMUM) {
    // Can vote
}
```

---

## Performance Optimization Workflow

### Step 1: Measure Current Performance

```bash
# Enable performance profiling
docker exec php php console.php performance:enable

# Profile endpoint
docker exec php php console.php performance:profile /api/users

# Check slow queries
docker exec php tail -f /var/log/mysql/slow-queries.log
```

---

### Step 2: Identify Bottlenecks

**Performance Profiling**:
```php
use App\Framework\Performance\PerformanceCollector;

$collector = new PerformanceCollector();

$collector->startMeasurement('expensive_operation');

// Expensive operation
$results = $this->heavyComputation();

$collector->endMeasurement('expensive_operation');

// View results
foreach ($collector->getMeasurements() as $measurement) {
    Logger::info('[Performance]', [
        'operation' => $measurement->name,
        'duration' => $measurement->duration->toMilliseconds()
    ]);
}
```

**Check N+1 Queries**:
```bash
docker exec php php console.php db:detect-n-plus-one /api/users
```

---

### Step 3: Optimize

**Cache Expensive Operations**:

```php
use App\Framework\Cache\{CacheKey, CacheItem};
use App\Framework\Core\ValueObjects\Duration;

public function getExpensiveData(): array
{
    $cacheKey = CacheKey::fromString('expensive_data');

    return $this->cache->remember(
        $cacheKey,
        fn() => $this->computeExpensiveData(),
        Duration::fromMinutes(10)
    );
}
```

**Fix N+1 Queries**:
```php
// ❌ Before: N+1 queries
$users = $this->userRepository->findAll();
foreach ($users as $user) {
    $profile = $user->getProfile(); // Separate query each time
}

// ✅ After: Eager loading
$users = $this->userRepository->findAllWithProfiles();
// Single JOIN query
```

**Add Database Indexes**:
```php
// Create migration
$schema->table('users', function (Blueprint $table) {
    // Add index for frequently queried column
    $table->index('email');

    // Composite index for common WHERE clauses
    $table->index(['status', 'created_at']);
});
```

---

### Step 4: Verify Improvements

```bash
# Re-profile endpoint
docker exec php php console.php performance:profile /api/users

# Compare before/after metrics
docker exec php php console.php performance:compare before.json after.json
```

---

### Performance Optimization Checklist

- [ ] Identify bottleneck (profiling data)
- [ ] Set performance target (e.g., <200ms response time)
- [ ] Implement optimization
- [ ] Measure improvement
- [ ] Verify no functional regression
- [ ] Document optimization
- [ ] Monitor in production

---

## Best Practices

### General Development Guidelines

**1. Follow Framework Patterns**:
- Use Value Objects instead of primitives
- Readonly classes by default
- Final classes (no inheritance)
- Explicit dependency injection
- Event-driven architecture

**2. Security First**:
- Validate all user input
- Use parameterized queries
- Implement authentication/authorization
- Never expose sensitive data in logs
- Follow OWASP guidelines

**3. Performance Awareness**:
- Profile before optimizing
- Cache expensive operations
- Avoid N+1 queries
- Use batch operations
- Monitor production metrics

**4. Test Everything**:
- Unit tests for domain logic
- Integration tests for API endpoints
- Edge case testing
- Regression tests for bug fixes
- Performance tests for critical paths

**5. Documentation**:
- Update API documentation
- Document complex business logic
- Maintain changelog
- Code should be self-documenting

---

### Code Quality Checklist

**Before Committing**:
- [ ] Run `composer cs` (code style check)
- [ ] Run `./vendor/bin/pest` (all tests pass)
- [ ] Run `composer reload` (autoloader updated)
- [ ] Check for commented-out code
- [ ] Verify no debug statements left
- [ ] Update documentation
- [ ] Review your own changes first

**Before Merging**:
- [ ] All CI checks pass
- [ ] Code reviewed by peer
- [ ] No merge conflicts
- [ ] Migration tested
- [ ] Performance impact assessed
- [ ] Security implications considered
- [ ] Changelog updated

---

### Development Environment Setup

**Initial Setup**:
```bash
# Clone repository
git clone <repository-url>
cd michaelschiemer

# Copy environment file
cp .env.example .env

# Start Docker containers
make up

# Install dependencies
composer install
npm install

# Run migrations
docker exec php php console.php db:migrate

# Build frontend assets
npm run build

# Verify setup
curl -k https://localhost/health
```

**Daily Development**:
```bash
# Start services
make up

# Watch frontend changes
npm run dev

# Run tests
./vendor/bin/pest --watch

# Check logs
make logs
```

---

**Last Updated**: 2025-01-28
**Framework Version**: 2.x
