This commit is contained in:
Mirko Janssen 2025-11-04 22:51:54 +01:00 committed by GitHub
commit 0f7fbf5029
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 2881 additions and 0 deletions

View file

@ -0,0 +1,320 @@
# Create Module
Create a new module in the Foundation framework following Domain-Driven Design principles and clean architecture.
## When to use this skill
- User asks to "create a new module"
- User asks to "add a module"
- User asks to "scaffold a module"
- User wants to add new business functionality
- User mentions "new feature module"
## Steps
1. **Create Module Directory Structure**
Create the base directory and three-layer architecture:
```bash
mkdir -p src/Modules/{ModuleName}/Domain
mkdir -p src/Modules/{ModuleName}/Application
mkdir -p src/Modules/{ModuleName}/Infrastructure/Api
mkdir -p src/Modules/{ModuleName}/Infrastructure/Web
mkdir -p src/Modules/{ModuleName}/Infrastructure/Database/Commands
mkdir -p src/Modules/{ModuleName}/Infrastructure/Database/Queries
```
2. **Create Domain Layer** (Pure business logic)
Create domain entities, value objects, and repository interfaces:
```php
// src/Modules/{ModuleName}/Domain/{Entity}.php
<?php
namespace Foundation\Modules\{ModuleName}\Domain;
final class {Entity}
{
public function __construct(
private int $id,
// Add properties
) {}
public function getId(): int { return $this->id; }
// Add getters and business methods
}
```
```php
// src/Modules/{ModuleName}/Domain/{Repository}Interface.php
<?php
namespace Foundation\Modules\{ModuleName}\Domain;
interface {Repository}Interface
{
public function findById(int $id): ?{Entity};
public function save({Entity} $entity): void;
}
```
3. **Create Application Layer** (Use cases)
Create application services that orchestrate domain logic:
```php
// src/Modules/{ModuleName}/Application/{UseCase}/{UseCase}.php
<?php
namespace Foundation\Modules\{ModuleName}\Application\{UseCase};
use Foundation\Modules\{ModuleName}\Domain\{Repository}Interface;
final class {UseCase}
{
public function __construct(
private {Repository}Interface $repository
) {}
public function execute(/* parameters */): mixed
{
// Use case logic
}
}
```
4. **Create Infrastructure Layer** (External implementations)
**a) Create Repository Implementation:**
```php
// src/Modules/{ModuleName}/Infrastructure/Database/{Repository}.php
<?php
namespace Foundation\Modules\{ModuleName}\Infrastructure\Database;
use Foundation\Modules\{ModuleName}\Domain\{Entity};
use Foundation\Modules\{ModuleName}\Domain\{Repository}Interface;
final class {Repository} implements {Repository}Interface
{
public function __construct(
private FetchByIdQuery $fetchById,
private SaveCommand $save
) {}
public function findById(int $id): ?{Entity}
{
return $this->fetchById->execute($id);
}
public function save({Entity} $entity): void
{
$this->save->execute($entity);
}
}
```
**b) Create Database Commands/Queries:**
```php
// src/Modules/{ModuleName}/Infrastructure/Database/Queries/FetchByIdQuery.php
<?php
namespace Foundation\Modules\{ModuleName}\Infrastructure\Database\Queries;
use PDO;
use Foundation\Modules\{ModuleName}\Domain\{Entity};
final class FetchByIdQuery
{
public function __construct(private PDO $pdo) {}
public function execute(int $id): ?{Entity}
{
$stmt = $this->pdo->prepare("SELECT * FROM {table} WHERE id = ?");
$stmt->execute([$id]);
$data = $stmt->fetch(PDO::FETCH_ASSOC);
return $data ? new {Entity}(/* map data */) : null;
}
}
```
**c) Create Controller:**
```php
// src/Modules/{ModuleName}/Infrastructure/Api/{Controller}.php
<?php
namespace Foundation\Modules\{ModuleName}\Infrastructure\Api;
use Foundation\Core\Infrastructure\ControllerInterface;
use Foundation\Core\Routing\Attributes\Get;
use Foundation\Core\Routing\Attributes\Post;
use Foundation\Core\Routing\Attributes\Group;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
#[Group('/api/{module-name}')]
final class {Controller} implements ControllerInterface
{
public function __construct(
private {UseCase} $useCase
) {}
#[Get('')]
public function index(
ServerRequestInterface $request,
ResponseInterface $response
): ResponseInterface {
// Controller logic
}
}
```
5. **Create Service Provider**
Create the service provider to register all module services:
```php
// src/Modules/{ModuleName}/{ModuleName}ServiceProvider.php
<?php
namespace Foundation\Modules\{ModuleName};
use Foundation\Core\Application\ServiceProvider\ServiceProvider;
use Foundation\Core\DependencyInjection\InflectableContainer;
use Foundation\Modules\{ModuleName}\Domain\{Repository}Interface;
use Foundation\Modules\{ModuleName}\Infrastructure\Database\{Repository};
use Foundation\Modules\{ModuleName}\Infrastructure\Database\Commands\*;
use Foundation\Modules\{ModuleName}\Infrastructure\Database\Queries\*;
use Foundation\Modules\{ModuleName}\Application\{UseCase}\*;
use Foundation\Modules\{ModuleName}\Infrastructure\Api\{Controller};
final class {ModuleName}ServiceProvider extends ServiceProvider
{
public function register(InflectableContainer $container): void
{
// Register queries
$container->register(FetchByIdQuery::class, [\PDO::class]);
// Register commands
$container->register(SaveCommand::class, [\PDO::class]);
// Register repository
$container->bind(
{Repository}Interface::class,
{Repository}::class,
[FetchByIdQuery::class, SaveCommand::class]
);
// Register use cases
$container->register(
{UseCase}::class,
[{Repository}Interface::class]
);
// Register controllers (routes auto-discovered via attributes)
$container->register(
{Controller}::class,
[{UseCase}::class]
);
}
}
```
6. **Refresh Autoloader**
```bash
make dump-autoload
```
## Verification
1. **Check Module is Auto-Discovered**
The `ModuleLoader` bootstrapper automatically discovers service providers in `src/Modules/*/`.
No additional registration needed.
2. **Verify Routes are Registered**
Access the controller endpoint to verify routes are working:
```bash
curl http://localhost:8000/api/{module-name}
```
3. **Check Service Container**
Verify services are properly registered by accessing them in a controller or test.
## Layer Dependency Rules
**IMPORTANT**: Always follow these strict dependency rules:
- **Domain Layer**: NO dependencies on other layers
- Only pure PHP and domain concepts
- No framework dependencies
- No database or HTTP concerns
- **Application Layer**: Can depend on Domain only
- Orchestrates domain logic
- Defines use cases
- No framework dependencies
- **Infrastructure Layer**: Can depend on Application and itself
- Implements repository interfaces
- Contains controllers, commands, queries
- Has framework dependencies
## Troubleshooting
### Module Not Auto-Discovered
**Problem**: Service provider not loaded automatically.
**Solution**:
1. Verify service provider is in: `src/Modules/{ModuleName}/{ModuleName}ServiceProvider.php`
2. Verify it extends `Foundation\Core\Application\ServiceProvider\ServiceProvider`
3. Check namespace matches directory structure
4. Run `make dump-autoload`
### Routes Not Working
**Problem**: Controller routes not accessible.
**Solution**:
1. Verify controller implements `Foundation\Core\Infrastructure\ControllerInterface`
2. Check route attributes are properly imported and used
3. Verify controller is registered in service provider
4. Check for route conflicts with existing routes
### Autoloading Issues
**Problem**: Class not found errors.
**Solution**:
```bash
make dump-autoload
```
Verify namespace matches directory structure following PSR-4:
- `Foundation\Modules\{ModuleName}``src/Modules/{ModuleName}`
## Examples
See existing modules for reference:
- `src/Modules/WelcomeScreen/` - Complete example module
## Quick Checklist
- [ ] Created Domain layer (entities, interfaces)
- [ ] Created Application layer (use cases)
- [ ] Created Infrastructure layer (controllers, repositories, commands, queries)
- [ ] Created Service Provider
- [ ] Service provider extends `ServiceProvider`
- [ ] Service provider in correct location
- [ ] Controllers implement `ControllerInterface`
- [ ] Routes use attributes (#[Get], #[Post], etc.)
- [ ] Repository interfaces in Domain layer
- [ ] Repository implementations in Infrastructure layer
- [ ] Followed layer dependency rules
- [ ] Ran `make dump-autoload`
- [ ] Verified routes are accessible

View file

@ -0,0 +1,364 @@
# Database Operations
Perform common database operations in the Foundation framework Docker environment.
## When to use this skill
- User asks to "import database schema"
- User asks to "backup database"
- User asks to "restore database"
- User asks to "access database"
- User asks to "export database"
- User mentions "database migration" or "schema setup"
- Setting up project for first time
- Need to reset database to clean state
## Steps
### Import Database Schema
1. **Import SQL Schema File**
```bash
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
```
This imports the database schema from `database/schema.sql` into the `foundation` database.
### Access Database CLI
2. **Access MySQL Command Line**
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password foundation
```
You'll be in the MySQL CLI. Common commands:
```sql
-- Show all tables
SHOW TABLES;
-- Describe table structure
DESCRIBE table_name;
-- Query data
SELECT * FROM table_name;
-- Exit
exit;
```
### Backup Database
3. **Export Database to File**
```bash
docker compose exec db mysqldump -u foundation_user -pfoundation_password foundation > backup.sql
```
Creates `backup.sql` in current directory with complete database dump.
4. **Export with Timestamp**
```bash
docker compose exec db mysqldump -u foundation_user -pfoundation_password foundation > backup-$(date +%Y%m%d-%H%M%S).sql
```
Creates timestamped backup file (e.g., `backup-20240115-143022.sql`).
### Restore Database
5. **Restore from Backup**
```bash
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < backup.sql
```
Restores database from backup file.
### Reset Database
6. **Drop and Recreate Database**
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password -e "DROP DATABASE IF EXISTS foundation; CREATE DATABASE foundation;"
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
```
Completely resets database to clean state from schema file.
### Access via phpMyAdmin
7. **Use phpMyAdmin GUI**
- Open browser: http://localhost:8080
- Server: `db`
- Username: `foundation_user`
- Password: `foundation_password`
- Database: `foundation`
## Verification
### Verify Import Success
1. **Check Tables Exist**
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password foundation -e "SHOW TABLES;"
```
Should list all tables from the schema.
2. **Verify Table Structure**
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password foundation -e "DESCRIBE users;"
```
Shows structure of `users` table (adjust table name as needed).
### Verify Backup Success
```bash
# Check file was created and has content
ls -lh backup.sql
head -n 20 backup.sql
```
Should show file with SQL dump content.
## Common Database Tasks
### Create New Table
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password foundation << EOF
CREATE TABLE example (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
EOF
```
### Run SQL File
```bash
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < path/to/file.sql
```
### Execute Single SQL Command
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password foundation -e "SELECT COUNT(*) FROM users;"
```
### Export Specific Table
```bash
docker compose exec db mysqldump -u foundation_user -pfoundation_password foundation table_name > table_backup.sql
```
### Copy Database
```bash
# Backup
docker compose exec db mysqldump -u foundation_user -pfoundation_password foundation > temp_backup.sql
# Restore to new database
docker compose exec db mysql -u foundation_user -pfoundation_password -e "CREATE DATABASE foundation_copy;"
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation_copy < temp_backup.sql
```
## Troubleshooting
### Connection Refused
**Problem**: Can't connect to database.
**Solution**:
1. Check database container is running:
```bash
docker compose ps
```
2. Verify database service is healthy:
```bash
docker compose logs db
```
3. Restart database:
```bash
docker compose restart db
```
### Access Denied
**Problem**: Authentication failed with error "Access denied for user".
**Solution**:
1. Verify credentials in command match Docker environment:
- Username: `foundation_user`
- Password: `foundation_password`
- Database: `foundation`
2. Check environment variables in `docker-compose.yml`
3. If changed, rebuild containers:
```bash
make down
make up
```
### Schema Import Errors
**Problem**: Import fails with SQL syntax errors.
**Solution**:
1. Check SQL file syntax is valid
2. Verify file encoding (should be UTF-8)
3. Check for incompatible MySQL version syntax
4. Try importing via phpMyAdmin to see detailed error
### Table Already Exists
**Problem**: Import fails because tables already exist.
**Solution**:
**Option 1**: Drop database first:
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password -e "DROP DATABASE foundation; CREATE DATABASE foundation;"
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
```
**Option 2**: Use `IF NOT EXISTS` in schema:
```sql
CREATE TABLE IF NOT EXISTS users (...);
```
### Backup File Too Large
**Problem**: Backup file is very large and slow.
**Solution**:
1. **Compress during backup**:
```bash
docker compose exec db mysqldump -u foundation_user -pfoundation_password foundation | gzip > backup.sql.gz
```
2. **Restore from compressed**:
```bash
gunzip < backup.sql.gz | docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation
```
### Database Locked
**Problem**: Operations timeout or fail with "database is locked".
**Solution**:
1. Check for long-running queries:
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password foundation -e "SHOW PROCESSLIST;"
```
2. Kill problematic query (get ID from processlist):
```bash
docker compose exec db mysql -u foundation_user -pfoundation_password foundation -e "KILL <process_id>;"
```
## Advanced Operations
### Database Performance Analysis
```bash
# Show database size
docker compose exec db mysql -u foundation_user -pfoundation_password foundation -e "
SELECT
table_name AS 'Table',
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS 'Size (MB)'
FROM information_schema.TABLES
WHERE table_schema = 'foundation'
ORDER BY (data_length + index_length) DESC;
"
```
### Export Structure Only (No Data)
```bash
docker compose exec db mysqldump -u foundation_user -pfoundation_password --no-data foundation > schema-only.sql
```
### Export Data Only (No Structure)
```bash
docker compose exec db mysqldump -u foundation_user -pfoundation_password --no-create-info foundation > data-only.sql
```
### Create Migration File
```bash
# Export current state as migration
docker compose exec db mysqldump -u foundation_user -pfoundation_password foundation > database/migrations/$(date +%Y%m%d_%H%M%S)_migration.sql
```
## Database Connection Parameters
**Environment Variables** (in Docker):
```env
DB_HOST=db
DB_PORT=3306
DB_DATABASE=foundation
DB_USERNAME=foundation_user
DB_PASSWORD=foundation_password
```
**Connection from Host** (outside Docker):
```bash
mysql -h 127.0.0.1 -P 3306 -u foundation_user -pfoundation_password foundation
```
**PDO Connection String** (in PHP):
```php
$dsn = "mysql:host=db;port=3306;dbname=foundation;charset=utf8mb4";
$pdo = new PDO($dsn, 'foundation_user', 'foundation_password');
```
## Quick Reference
```bash
# Import schema
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
# Backup database
docker compose exec db mysqldump -u foundation_user -pfoundation_password foundation > backup.sql
# Restore database
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < backup.sql
# Access MySQL CLI
docker compose exec db mysql -u foundation_user -pfoundation_password foundation
# Execute SQL command
docker compose exec db mysql -u foundation_user -pfoundation_password foundation -e "SHOW TABLES;"
# Reset database
docker compose exec db mysql -u foundation_user -pfoundation_password -e "DROP DATABASE foundation; CREATE DATABASE foundation;"
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
# Compressed backup
docker compose exec db mysqldump -u foundation_user -pfoundation_password foundation | gzip > backup.sql.gz
# View logs
docker compose logs db
# Restart database
docker compose restart db
```
## Best Practices
1. **Regular Backups** - Backup before major changes
2. **Timestamped Backups** - Use timestamps in backup filenames
3. **Test Restores** - Periodically verify backups can be restored
4. **Version Control Schema** - Keep schema files in git
5. **Use Migrations** - For production, use migration system
6. **Separate Test Data** - Keep test data separate from schema
7. **Document Changes** - Comment complex SQL in schema files
8. **Review Before Import** - Check schema files before importing
9. **Monitor Size** - Watch database growth over time
10. **Use Transactions** - Wrap multiple operations in transactions
## Security Notes
1. **Don't Commit Credentials** - Never commit database passwords
2. **Change Default Password** - Use strong passwords in production
3. **Limit Privileges** - Use least privilege principle for users
4. **Encrypt Backups** - Encrypt backup files if they contain sensitive data
5. **Secure phpMyAdmin** - Disable or secure phpMyAdmin in production

View file

@ -0,0 +1,433 @@
# Debug Setup
Configure Xdebug for debugging PHP applications in the Foundation framework Docker environment.
## When to use this skill
- User asks to "set up debugging"
- User asks to "configure xdebug"
- User asks "how to debug"
- User wants to "use breakpoints"
- User mentions "step through code"
- Setting up IDE for first time
- Debugging not working
## Prerequisites
- Docker environment running (`make up`)
- IDE installed (PHPStorm or VS Code)
- Xdebug already installed in Docker container (included by default)
## Steps for PHPStorm
### 1. Configure PHP Interpreter
**a) Open Interpreter Settings**
- Go to `Settings/Preferences > PHP`
- Click `...` next to CLI Interpreter
**b) Add Docker Compose Interpreter**
- Click `+``From Docker, Vagrant, VM, WSL...`
- Select `Docker Compose`
- Configuration file: `docker-compose.yml`
- Service: `app`
- Click `OK`
**c) Verify Configuration**
- PHP version should show: `8.1.x`
- Xdebug should be listed under Configuration file
### 2. Configure Debug Settings
**a) Open Debug Settings**
- Go to `Settings/Preferences > PHP > Debug`
**b) Configure Xdebug**
- Xdebug port: `9003`
- Check: `Can accept external connections`
- Uncheck: `Break at first line in PHP scripts` (optional)
- Max simultaneous connections: `5`
### 3. Configure Server Mapping
**a) Open Server Settings**
- Go to `Settings/Preferences > PHP > Servers`
**b) Add New Server**
- Click `+` to add new server
- Name: `foundation-docker`
- Host: `localhost`
- Port: `8000`
- Debugger: `Xdebug`
- Check: `Use path mappings`
**c) Configure Path Mappings**
- Project root: `/var/www/html`
- Example:
```
/home/user/foundation → /var/www/html
```
### 4. Start Debugging Session
**a) Set Breakpoint**
- Click in the gutter next to line number in any PHP file
- Red dot should appear
**b) Start Listening**
- Click `Start Listening for PHP Debug Connections` (phone icon) in toolbar
- Icon should turn green
**c) Trigger Request**
- Open browser: http://localhost:8000
- PHPStorm should pause at breakpoint
## Steps for VS Code
### 1. Install PHP Debug Extension
**a) Install Extension**
- Open Extensions panel (`Ctrl+Shift+X` or `Cmd+Shift+X`)
- Search for: `PHP Debug`
- Install: `PHP Debug` by Xdebug
### 2. Configure Launch Configuration
**a) Create launch.json**
- Click `Run > Add Configuration...`
- Select `PHP` from dropdown
**b) Edit launch.json**
Create `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
"log": true
}
]
}
```
### 3. Start Debugging Session
**a) Set Breakpoint**
- Click in the gutter next to line number
- Red dot should appear
**b) Start Debug Session**
- Press `F5` or click `Run > Start Debugging`
- Select `Listen for Xdebug`
**c) Trigger Request**
- Open browser: http://localhost:8000
- VS Code should pause at breakpoint
## Verification
### Test Debug Connection
1. **Set Breakpoint**
```php
// In any controller, e.g., src/Modules/WelcomeScreen/Infrastructure/Web/WelcomeController.php
public function index(): ResponseInterface
{
$test = "debug test"; // Set breakpoint on this line
// ...
}
```
2. **Start Listening** (in IDE)
3. **Access Application**
```bash
curl http://localhost:8000
# or open in browser
```
4. **Verify Pause**
- IDE should pause execution at breakpoint
- Variables panel should show local variables
- Call stack should show current execution path
### Debug Controls
Once paused at breakpoint:
**PHPStorm**:
- `F8` - Step Over
- `F7` - Step Into
- `Shift+F8` - Step Out
- `F9` - Resume Program
- `Ctrl+F8` - Toggle Breakpoint
**VS Code**:
- `F10` - Step Over
- `F11` - Step Into
- `Shift+F11` - Step Out
- `F5` - Continue
- `F9` - Toggle Breakpoint
## Troubleshooting
### Breakpoint Not Hit
**Problem**: Debugger doesn't pause at breakpoint.
**Diagnostic**:
```bash
# Check Xdebug is loaded
docker compose exec app php -v
# Should show:
# with Xdebug v3.x.x
```
**Solutions**:
**A) Verify Xdebug Configuration**
```bash
docker compose exec app php -i | grep xdebug
```
Should show:
- `xdebug.mode = debug`
- `xdebug.start_with_request = yes`
- `xdebug.client_host = host.docker.internal`
- `xdebug.client_port = 9003`
**B) Check IDE is Listening**
- Verify debug listener is active (green phone icon in PHPStorm)
- Verify debug session started in VS Code
**C) Verify Path Mappings**
- Project root must map to `/var/www/html`
- Check for typos in paths
### Connection Refused
**Problem**: IDE shows "Connection refused" or timeout.
**Solutions**:
**A) Check Port Configuration**
- IDE listening on port 9003
- Xdebug connecting to port 9003
- No firewall blocking port 9003
**B) Verify Docker Network**
```bash
# Test connection from container
docker compose exec app ping -c 3 host.docker.internal
```
**C) Check Xdebug Configuration**
```bash
docker compose exec app cat /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
```
### Path Mapping Issues
**Problem**: Debugger can't find source files.
**Solutions**:
**A) Verify Mapping**
- Local path: `/home/user/foundation`
- Container path: `/var/www/html`
- Must match exactly
**B) Check Working Directory**
```bash
docker compose exec app pwd
# Should output: /var/www/html
```
**C) Restart IDE and Docker**
```bash
# Restart Docker
make down
make up
# Restart IDE completely
```
### Multiple Debug Sessions
**Problem**: Multiple IDE instances or debug sessions conflict.
**Solutions**:
**A) Close Other IDEs**
- Only one IDE should listen for Xdebug at a time
**B) Change Port in One IDE**
- Use different port (e.g., 9004) in second IDE
- Update Xdebug config to match
### Browser Extension Conflicts
**Problem**: Debug session starts unexpectedly or not at all.
**Solutions**:
**A) Install Xdebug Helper**
- Chrome: Install "Xdebug Helper" extension
- Firefox: Install "Xdebug Helper" addon
**B) Configure Extension**
- Set IDE key to `PHPSTORM` or `VSCODE`
- Enable debug mode in extension icon
## Advanced Configuration
### Xdebug Configuration File
Location in container: `/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini`
Example configuration:
```ini
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.log=/tmp/xdebug.log
xdebug.log_level=0
```
### Enable Xdebug Logging
For troubleshooting:
```bash
# Edit Xdebug config
docker compose exec app bash -c "echo 'xdebug.log=/tmp/xdebug.log' >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini"
docker compose exec app bash -c "echo 'xdebug.log_level=7' >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini"
# Restart container
docker compose restart app
# View log
docker compose exec app tail -f /tmp/xdebug.log
```
### Conditional Breakpoints
**PHPStorm**:
- Right-click breakpoint → Add condition
- Example: `$userId === 123`
**VS Code**:
- Right-click breakpoint → Edit Breakpoint
- Add expression: `$userId === 123`
### Remote Debugging
For debugging CLI scripts:
```bash
# Set environment variable
docker compose exec app bash
export XDEBUG_SESSION=PHPSTORM
# Run script
php script.php
```
## Testing Specific Scenarios
### Debug API Requests
```bash
# With debug cookie
curl -b "XDEBUG_SESSION=PHPSTORM" http://localhost:8000/api/endpoint
```
### Debug CLI Commands
```bash
# Start listening in IDE first
docker compose exec app bash
export XDEBUG_SESSION=PHPSTORM
php artisan command
```
### Debug Tests
```bash
# Start listening in IDE first
docker compose exec app bash
export XDEBUG_SESSION=PHPSTORM
vendor/bin/phpunit tests/Unit/MyTest.php
```
## Best Practices
1. **Disable Xdebug for Tests** (faster execution)
```bash
docker compose exec app php -d xdebug.mode=off vendor/bin/phpunit
```
2. **Use Logging Breakpoints** (don't pause execution)
- Evaluate and log instead of stopping
3. **Conditional Breakpoints** (reduce noise)
- Only break when specific conditions met
4. **Watch Expressions** (monitor variables)
- Add variables to watch list for continuous monitoring
5. **Clear Breakpoints** (avoid clutter)
- Remove breakpoints when done debugging
## Quick Reference
### PHPStorm
```
Settings > PHP > CLI Interpreter → Add Docker Compose (app service)
Settings > PHP > Debug → Port 9003, Accept external connections
Settings > PHP > Servers → Add server, path mapping: /var/www/html
Start Listening (phone icon) → Set breakpoint → Access app
```
### VS Code
```json
// .vscode/launch.json
{
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
}
}
```
```
F5 to start → Set breakpoint → Access app
```
### Xdebug Info
```bash
# Check Xdebug is loaded
docker compose exec app php -v
# View Xdebug configuration
docker compose exec app php -i | grep xdebug
# View config file
docker compose exec app cat /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
```
### Common Issues
- Not hitting breakpoint → Check IDE is listening, verify path mappings
- Connection refused → Check port 9003, verify Xdebug config
- Wrong file shown → Fix path mappings
- Multiple sessions → Close other IDEs listening on same port

View file

@ -0,0 +1,155 @@
# Docker Setup
Initialize and configure the Docker development environment for Foundation framework.
## When to use this skill
- User asks to "set up docker environment"
- User asks to "initialize development environment"
- User asks to "start the project"
- User mentions "docker setup" or "docker configuration"
- First time project setup
## Steps
1. **Verify Prerequisites**
```bash
docker --version
docker compose version
```
Ensure Docker and Docker Compose are installed on the system.
2. **Set User Permissions (Linux/macOS)**
```bash
export USER_ID=$(id -u) && export GROUP_ID=$(id -g)
```
This ensures files created in containers have correct ownership.
3. **Start Docker Environment**
```bash
make up
```
This command:
- Builds Docker images if needed
- Starts app, db, and phpmyadmin containers
- Creates necessary networks and volumes
4. **Install Dependencies**
```bash
make install
```
Installs all Composer dependencies inside the app container.
5. **Import Database Schema** (if schema exists)
```bash
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
```
6. **Copy Environment Configuration** (if not exists)
```bash
cp .env.example .env
```
Edit `.env` if custom configuration is needed (usually Docker defaults work).
## Verification
1. **Check Container Status**
```bash
docker compose ps
```
All three containers (app, db, phpmyadmin) should be in "running" state.
2. **Verify Application Access**
- Open browser: http://localhost:8000
- Should see the application homepage
3. **Verify Database Access**
- Open browser: http://localhost:8080 (phpMyAdmin)
- Login with: foundation_user / foundation_password
- Should see "foundation" database
4. **Test Container Shell Access**
```bash
make shell
```
Should enter the app container bash shell. Type `exit` to leave.
## Troubleshooting
### Port Conflicts
**Problem**: Error about port 8000, 8080, or 3306 already in use.
**Solution**:
```bash
# Check what's using the port (example for port 8000)
sudo lsof -i :8000
# Stop conflicting service or modify docker-compose.yml ports
```
### Permission Errors
**Problem**: Files created by Docker have wrong ownership.
**Solution**:
```bash
# Set user/group IDs and rebuild
export USER_ID=$(id -u) && export GROUP_ID=$(id -g)
make down
make up
```
### Container Won't Start
**Problem**: Containers fail to start or crash immediately.
**Solution**:
```bash
# Check logs for specific container
docker compose logs app
docker compose logs db
# Try rebuilding
make down
docker compose up -d --build
```
### Database Connection Failed
**Problem**: Application can't connect to database.
**Solution**:
1. Verify database container is running: `docker compose ps`
2. Check environment variables in `.env` match Docker defaults:
```
DB_HOST=db
DB_PORT=3306
DB_DATABASE=foundation
DB_USERNAME=foundation_user
DB_PASSWORD=foundation_password
```
3. Restart containers: `make down && make up`
## Quick Reference
```bash
# Start environment
make up
# Stop environment
make down
# View logs
docker compose logs -f app
# Restart a service
docker compose restart app
# Rebuild containers
make down
docker compose up -d --build
# Access container shell
make shell
```

View file

@ -0,0 +1,332 @@
# Run Tests
Execute the testing suite for Foundation framework using PHPUnit.
## When to use this skill
- User asks to "run tests"
- User asks to "execute test suite"
- User asks to "check if tests pass"
- User mentions "test coverage"
- User asks to "run unit tests" or "run integration tests"
- After making code changes that need verification
## Steps
### Run All Tests
1. **Execute Full Test Suite**
```bash
make test
```
This runs all unit and integration tests.
### Run Specific Test Suites
2. **Run Unit Tests Only**
```bash
make test-unit
```
Unit tests focus on testing individual components in isolation.
3. **Run Integration Tests Only**
```bash
make test-integration
```
Integration tests verify components work together correctly.
### Generate Coverage Report
4. **Run Tests with Coverage**
```bash
make test-coverage
```
Generates an HTML coverage report in `coverage-html/` directory.
5. **View Coverage Report**
```bash
# Open in browser (adjust path as needed)
open coverage-html/index.html
# or
xdg-open coverage-html/index.html
```
### Run Specific Test Files
6. **Run Single Test File** (if needed)
```bash
docker compose exec app vendor/bin/phpunit tests/Unit/Path/To/TestFile.php
```
7. **Run Single Test Method** (if needed)
```bash
docker compose exec app vendor/bin/phpunit --filter testMethodName
```
## Verification
### Successful Test Run
```
PHPUnit 10.x.x
................................................... 50 / 100 ( 50%)
.................................................. 100 / 100 (100%)
Time: 00:01.234, Memory: 10.00 MB
OK (100 tests, 250 assertions)
```
### Failed Test Example
```
F
Time: 00:00.123, Memory: 8.00 MB
There was 1 failure:
1) Foundation\Tests\Unit\ExampleTest::testExample
Failed asserting that false is true.
/var/www/html/tests/Unit/ExampleTest.php:15
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
```
## Test Organization
Tests are organized by type:
```
tests/
├── Unit/ # Unit tests
│ ├── Core/
│ └── Modules/
└── Integration/ # Integration tests
├── Api/
└── Database/
```
### Unit Tests
- Test individual classes in isolation
- Mock dependencies
- Fast execution
- No database or HTTP calls
**Example:**
```php
namespace Foundation\Tests\Unit\Core;
use PHPUnit\Framework\TestCase;
final class ExampleTest extends TestCase
{
public function testExample(): void
{
$this->assertTrue(true);
}
}
```
### Integration Tests
- Test components working together
- May use real database (test database)
- Test full request/response cycle
- Slower than unit tests
**Example:**
```php
namespace Foundation\Tests\Integration\Api;
use PHPUnit\Framework\TestCase;
final class ApiTest extends TestCase
{
public function testApiEndpoint(): void
{
// Test full HTTP request/response
}
}
```
## Troubleshooting
### Tests Not Found
**Problem**: PHPUnit can't find test files.
**Solution**:
1. Check phpunit.xml or phpunit.xml.dist configuration
2. Verify test files end with `Test.php`
3. Verify test classes extend `PHPUnit\Framework\TestCase`
4. Run `make dump-autoload`
### Database Connection Errors (Integration Tests)
**Problem**: Tests fail with database connection errors.
**Solution**:
1. Ensure Docker containers are running: `docker compose ps`
2. Check test environment configuration
3. Verify test database exists and is accessible
4. Check `.env` or test configuration for correct database credentials
### Memory Limit Errors
**Problem**: Tests fail with "Allowed memory size exhausted" error.
**Solution**:
```bash
# Increase memory limit for tests
docker compose exec app php -d memory_limit=512M vendor/bin/phpunit
```
Or modify `phpunit.xml`:
```xml
<php>
<ini name="memory_limit" value="512M"/>
</php>
```
### Slow Test Execution
**Problem**: Tests take too long to run.
**Solution**:
1. Run only unit tests during development: `make test-unit`
2. Run specific test files instead of full suite
3. Use `--stop-on-failure` flag to stop at first failure:
```bash
docker compose exec app vendor/bin/phpunit --stop-on-failure
```
### Coverage Report Not Generated
**Problem**: Coverage report directory is empty.
**Solution**:
1. Verify Xdebug is installed in Docker container
2. Check phpunit.xml coverage configuration
3. Run coverage command with verbose output:
```bash
docker compose exec app vendor/bin/phpunit --coverage-html=coverage-html --verbose
```
## Advanced Usage
### Parallel Test Execution
For faster execution (if paratest is installed):
```bash
docker compose exec app vendor/bin/paratest
```
### Watch Mode (Continuous Testing)
Using phpunit-watcher (if installed):
```bash
docker compose exec app vendor/bin/phpunit-watcher watch
```
### Test Filtering
```bash
# Run tests in specific namespace
docker compose exec app vendor/bin/phpunit --filter "Foundation\\Tests\\Unit\\Core"
# Run tests matching pattern
docker compose exec app vendor/bin/phpunit --filter testUserCreation
# Run tests from specific group
docker compose exec app vendor/bin/phpunit --group integration
```
## Best Practices
1. **Run tests before committing**
```bash
make test
```
2. **Run unit tests during development** (faster feedback)
```bash
make test-unit
```
3. **Run full suite before pushing**
```bash
make test && make static-analysis
```
4. **Check coverage periodically**
```bash
make test-coverage
```
5. **Write tests for new features** - Ensure new code is covered
6. **Keep tests fast** - Mock external dependencies in unit tests
7. **Use meaningful test names** - Test method names should describe what they test
## Quick Reference
```bash
# All tests
make test
# Unit tests only
make test-unit
# Integration tests only
make test-integration
# With coverage report
make test-coverage
# Single file
docker compose exec app vendor/bin/phpunit tests/Unit/Path/To/TestFile.php
# Single method
docker compose exec app vendor/bin/phpunit --filter testMethodName
# Stop on first failure
docker compose exec app vendor/bin/phpunit --stop-on-failure
# Verbose output
docker compose exec app vendor/bin/phpunit --verbose
```
## Test Writing Tips
1. **Follow AAA Pattern**
- Arrange: Set up test data
- Act: Execute the code under test
- Assert: Verify the results
2. **One Assertion Per Test** (when possible)
- Makes failures easier to diagnose
3. **Use Descriptive Names**
```php
// Good
public function testUserCanBeCreatedWithValidEmail(): void
// Bad
public function testUser(): void
```
4. **Test Edge Cases**
- Empty inputs
- Null values
- Boundary conditions
- Error cases
5. **Keep Tests Independent**
- Tests should not depend on each other
- Each test should set up its own data

View file

@ -0,0 +1,402 @@
# Static Analysis
Run static analysis tools to check code quality, type safety, and architectural boundaries in the Foundation framework.
## When to use this skill
- User asks to "run static analysis"
- User asks to "check code quality"
- User asks to "run phpstan" or "run deptrac"
- User asks to "analyze code"
- User mentions "type checking" or "architecture validation"
- Before committing code
- After making significant changes
## Steps
### Run Complete Static Analysis
1. **Run All Static Analysis Tools**
```bash
make static-analysis
```
This runs both PHPStan and Deptrac in sequence.
### Run Individual Tools
2. **Run PHPStan** (Type and Code Analysis)
```bash
make phpstan
```
PHPStan checks for:
- Type errors
- Undefined variables
- Invalid method calls
- Dead code
- Strict rules violations
3. **Run Deptrac** (Architecture Layer Analysis)
```bash
make deptrac
```
Deptrac validates:
- Layer dependency rules (Domain → Application → Infrastructure)
- Module boundaries
- Architectural violations
### Generate Baselines (When Needed)
4. **Generate PHPStan Baseline**
```bash
make phpstan-baseline
```
Creates `phpstan-baseline.neon` to suppress existing errors while preventing new ones.
5. **Generate Deptrac Baseline**
```bash
make deptrac-baseline
```
Creates `deptrac-baseline.yaml` to track existing architectural violations.
## Verification
### PHPStan Success
```
PHPStan - PHP Static Analysis Tool
[OK] No errors
```
### Deptrac Success
```
Deptrac
[OK] No violations found
```
### PHPStan Errors Example
```
------ --------------------------------------------------------
Line src/Modules/Example/Domain/Example.php
------ --------------------------------------------------------
15 Property Example::$name has no type hint
23 Method Example::getData() has no return type specified
45 Call to undefined method PDO::executeQuery()
------ --------------------------------------------------------
[ERROR] Found 3 errors
```
### Deptrac Violations Example
```
------ --------------------------------------------------------
From To
------ --------------------------------------------------------
Domain\Example (Domain Layer) Infrastructure\Database (Infrastructure Layer)
------ --------------------------------------------------------
[ERROR] Found 1 violation
Violation: Domain layer must not depend on Infrastructure layer
```
## Analysis Tools Overview
### PHPStan
**Purpose**: Static analysis for type safety and code quality
**Configuration**: `phpstan.neon` or `phpstan.neon.dist`
**Key Features**:
- Level-based strictness (0-9, higher = stricter)
- Type inference and checking
- Dead code detection
- Strict rules for code quality
**What It Checks**:
- Type mismatches
- Undefined variables and methods
- Invalid array access
- Return type compatibility
- Parameter type compatibility
- Property type hints
### Deptrac
**Purpose**: Architecture and dependency rule validation
**Configuration**: `deptrac.yaml` or `deptrac.yaml.dist`
**Key Features**:
- Layer dependency enforcement
- Module boundary validation
- Custom rule definition
**What It Checks**:
- Domain layer has no dependencies
- Application layer only depends on Domain
- Infrastructure layer only depends on Application
- No circular dependencies
- Custom architectural rules
## Troubleshooting
### PHPStan Errors After Dependency Updates
**Problem**: New errors appear after updating dependencies.
**Solution**:
1. Review and fix legitimate errors
2. If errors are unavoidable (third-party library issues):
```bash
make phpstan-baseline
```
3. Commit the baseline file
### Deptrac False Positives
**Problem**: Deptrac reports violations that are intentional or unavoidable.
**Solution**:
1. Review the violation - ensure it's truly acceptable
2. If legitimate, update `deptrac.yaml` to allow specific exception
3. Or generate baseline:
```bash
make deptrac-baseline
```
### PHPStan Memory Limit
**Problem**: PHPStan crashes with memory exhausted error.
**Solution**:
```bash
# Run with increased memory
docker compose exec app php -d memory_limit=1G vendor/bin/phpstan analyse
```
Or modify `phpstan.neon`:
```yaml
parameters:
memory_limit: 1G
```
### Slow Analysis
**Problem**: Static analysis takes too long.
**Solution**:
1. **Enable result cache** in `phpstan.neon`:
```yaml
parameters:
tmpDir: var/cache/phpstan
```
2. **Analyze specific paths** during development:
```bash
docker compose exec app vendor/bin/phpstan analyse src/Modules/MyModule
```
### Configuration Not Found
**Problem**: Tool can't find configuration file.
**Solution**:
1. Verify configuration file exists:
- PHPStan: `phpstan.neon` or `phpstan.neon.dist`
- Deptrac: `deptrac.yaml` or `deptrac.yaml.dist`
2. Check file is in project root
3. Verify file syntax is valid YAML/NEON
## Advanced Usage
### PHPStan Commands
```bash
# Analyze specific directory
docker compose exec app vendor/bin/phpstan analyse src/Modules/MyModule
# Different error level (0-9)
docker compose exec app vendor/bin/phpstan analyse --level=9
# Show progress
docker compose exec app vendor/bin/phpstan analyse --verbose
# Clear cache
docker compose exec app vendor/bin/phpstan clear-result-cache
```
### Deptrac Commands
```bash
# Analyze with specific configuration
docker compose exec app vendor/bin/deptrac analyse --config-file=deptrac.yaml
# Generate dependency graph
docker compose exec app vendor/bin/deptrac analyse --formatter=graphviz
# Different output format
docker compose exec app vendor/bin/deptrac analyse --formatter=console
```
## Common Layer Violations and Fixes
### Domain Depending on Infrastructure
**Violation**:
```
Domain\UserRepository → Infrastructure\Database\PDO
```
**Fix**:
Move repository interface to Domain, implementation to Infrastructure:
```php
// Domain/UserRepositoryInterface.php (in Domain layer)
interface UserRepositoryInterface
{
public function findById(int $id): ?User;
}
// Infrastructure/Database/UserRepository.php (in Infrastructure layer)
class UserRepository implements UserRepositoryInterface
{
public function __construct(private PDO $pdo) {}
}
```
### Application Depending on Infrastructure
**Violation**:
```
Application\UseCase → Infrastructure\Api\Controller
```
**Fix**:
Reverse the dependency - Controllers should call use cases, not vice versa:
```php
// Infrastructure/Api/UserController.php
class UserController
{
public function __construct(
private CreateUserUseCase $createUser // Application layer
) {}
}
```
## Best Practices
1. **Run Before Committing**
```bash
make test && make static-analysis
```
2. **Fix Issues Immediately** - Don't let violations accumulate
3. **Use Baselines Sparingly** - Fix issues rather than suppressing them
4. **Review Violations** - Understand why a violation occurs before suppressing
5. **Keep Configuration Strict** - Higher PHPStan levels catch more issues
6. **Respect Layer Boundaries** - Domain should never depend on outer layers
7. **Type Everything** - Add type hints to all methods and properties
## Integration with CI/CD
Add to your CI pipeline:
```bash
#!/bin/bash
set -e
echo "Running static analysis..."
make phpstan
make deptrac
echo "All checks passed!"
```
## Quick Reference
```bash
# Run all static analysis
make static-analysis
# PHPStan only
make phpstan
# Deptrac only
make deptrac
# Generate baselines
make phpstan-baseline
make deptrac-baseline
# PHPStan specific path
docker compose exec app vendor/bin/phpstan analyse src/Modules/MyModule
# Deptrac with graph output
docker compose exec app vendor/bin/deptrac analyse --formatter=graphviz
# Clear PHPStan cache
docker compose exec app vendor/bin/phpstan clear-result-cache
```
## Understanding Error Levels
### PHPStan Levels (0-9)
- **Level 0**: Basic checks, few false positives
- **Level 5**: Reasonable balance, good starting point
- **Level 9**: Maximum strictness, requires extensive type hints
Recommendation: Start at level 5, gradually increase to 9.
## Configuration Examples
### PHPStan Configuration
```yaml
# phpstan.neon
parameters:
level: 9
paths:
- src
tmpDir: var/cache/phpstan
excludePaths:
- src/old-code/
```
### Deptrac Configuration
```yaml
# deptrac.yaml
deptrac:
paths:
- ./src
layers:
- name: Domain
collectors:
- type: directory
regex: src/.*/Domain/.*
- name: Application
collectors:
- type: directory
regex: src/.*/Application/.*
- name: Infrastructure
collectors:
- type: directory
regex: src/.*/Infrastructure/.*
ruleset:
Domain: []
Application:
- Domain
Infrastructure:
- Application
```

View file

@ -0,0 +1,524 @@
# Troubleshoot Docker
Diagnostic steps and solutions for common Docker issues in the Foundation framework.
## When to use this skill
- User reports "Docker not working"
- User mentions "containers won't start"
- User reports "connection refused" errors
- User asks "why isn't the app working?"
- User mentions "port already in use"
- User reports "permission denied" errors
- Application not accessible via browser
- Database connection failures
## Diagnostic Steps
### Step 1: Check Container Status
1. **List All Containers**
```bash
docker compose ps
```
**Expected Output**:
```
NAME STATUS PORTS
foundation-app Up X minutes 0.0.0.0:8000->80/tcp
foundation-db Up X minutes 0.0.0.0:3306->3306/tcp
foundation-phpmyadmin Up X minutes 0.0.0.0:8080->80/tcp
```
All containers should show "Up" status.
### Step 2: Check Container Logs
2. **View Container Logs**
```bash
# All containers
docker compose logs
# Specific container
docker compose logs app
docker compose logs db
docker compose logs phpmyadmin
# Follow logs in real-time
docker compose logs -f app
```
Look for error messages, warnings, or stack traces.
### Step 3: Check Port Availability
3. **Check if Ports are Available**
```bash
# Check port 8000 (app)
sudo lsof -i :8000
# Check port 8080 (phpmyadmin)
sudo lsof -i :8080
# Check port 3306 (mysql)
sudo lsof -i :3306
```
If output shows other processes using these ports, you have a port conflict.
### Step 4: Verify Docker Service
4. **Check Docker Daemon Status**
```bash
docker --version
docker compose version
systemctl status docker # Linux
```
Ensure Docker daemon is running.
### Step 5: Test Application Access
5. **Test HTTP Endpoints**
```bash
# Test app
curl http://localhost:8000
# Test phpMyAdmin
curl http://localhost:8080
```
Should return HTML content, not connection errors.
## Common Issues and Solutions
### Issue 1: Containers Won't Start
**Symptoms**:
- `docker compose ps` shows containers with "Exit" status
- Containers restart repeatedly
**Diagnostic**:
```bash
docker compose logs app
docker compose logs db
```
**Solutions**:
**A) Port Conflict**
```bash
# Find process using port
sudo lsof -i :8000
# Kill process or change port in docker-compose.yml
```
**B) Configuration Error**
```bash
# Check docker-compose.yml syntax
docker compose config
# Rebuild containers
make down
docker compose up -d --build
```
**C) Previous Container Data Issues**
```bash
# Remove containers and volumes
docker compose down -v
# Restart fresh
make up
```
### Issue 2: Application Returns 500 Error
**Symptoms**:
- Browser shows "Internal Server Error"
- HTTP 500 status code
**Diagnostic**:
```bash
docker compose logs -f app
docker compose exec app tail -f storage/logs/app.log
```
**Solutions**:
**A) Check File Permissions**
```bash
# Fix permissions in container
docker compose exec app chown -R www-data:www-data storage/
docker compose exec app chmod -R 775 storage/
```
**B) Check PHP Errors**
```bash
# View PHP error log
docker compose exec app tail -f /var/log/apache2/error.log
```
**C) Missing Dependencies**
```bash
# Reinstall dependencies
make install
```
### Issue 3: Database Connection Failed
**Symptoms**:
- "Connection refused" to database
- "SQLSTATE[HY000] [2002]" errors
- Application can't connect to MySQL
**Diagnostic**:
```bash
# Check database container
docker compose ps db
# Check database logs
docker compose logs db
# Test connection from app container
docker compose exec app mysql -h db -u foundation_user -pfoundation_password foundation
```
**Solutions**:
**A) Database Container Not Running**
```bash
# Restart database
docker compose restart db
# Check startup logs
docker compose logs db
```
**B) Wrong Credentials**
```bash
# Verify environment variables
docker compose exec app env | grep DB_
# Should show:
# DB_HOST=db
# DB_PORT=3306
# DB_DATABASE=foundation
# DB_USERNAME=foundation_user
# DB_PASSWORD=foundation_password
```
**C) Database Not Initialized**
```bash
# Import schema
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
```
### Issue 4: Port Already in Use
**Symptoms**:
- Error: "port is already allocated"
- Error: "bind: address already in use"
**Diagnostic**:
```bash
sudo lsof -i :8000
sudo lsof -i :8080
sudo lsof -i :3306
```
**Solutions**:
**A) Stop Conflicting Service**
```bash
# If Apache/Nginx is running
sudo systemctl stop apache2
# or
sudo systemctl stop nginx
# If MySQL is running
sudo systemctl stop mysql
```
**B) Change Docker Ports**
Edit `docker-compose.yml`:
```yaml
services:
app:
ports:
- "8001:80" # Change 8000 to 8001
```
Then restart:
```bash
make down
make up
```
### Issue 5: Permission Denied Errors
**Symptoms**:
- Can't write to files
- Can't create directories
- Permission denied in logs
**Diagnostic**:
```bash
# Check file ownership
docker compose exec app ls -la /var/www/html/storage
# Check user in container
docker compose exec app whoami
```
**Solutions**:
**A) Fix Ownership (Linux/macOS)**
```bash
export USER_ID=$(id -u) && export GROUP_ID=$(id -g)
make down
make up
```
**B) Fix Permissions in Container**
```bash
docker compose exec app chown -R www-data:www-data /var/www/html
docker compose exec app chmod -R 775 /var/www/html/storage
```
### Issue 6: Changes Not Reflected
**Symptoms**:
- Code changes don't appear in browser
- Old version still running
**Diagnostic**:
```bash
# Check if volumes are mounted
docker compose exec app ls -la /var/www/html
```
**Solutions**:
**A) Clear Caches**
```bash
# Clear application cache
docker compose exec app rm -rf storage/cache/*
# Clear browser cache
# Use Ctrl+Shift+R or Cmd+Shift+R
```
**B) Restart Container**
```bash
docker compose restart app
```
**C) Rebuild Container**
```bash
make down
docker compose up -d --build
```
### Issue 7: Slow Performance
**Symptoms**:
- Application very slow to respond
- High CPU/memory usage
- Timeouts
**Diagnostic**:
```bash
# Check container resource usage
docker stats
# Check logs for errors
docker compose logs app
```
**Solutions**:
**A) Increase Docker Resources**
In Docker Desktop: Settings → Resources → Increase CPU/Memory
**B) Clear Logs**
```bash
docker compose exec app rm -f storage/logs/*
docker compose exec app truncate -s 0 /var/log/apache2/error.log
```
**C) Optimize Autoloader**
```bash
make dump-autoload
```
### Issue 8: Cannot Access Container Shell
**Symptoms**:
- `make shell` or `docker compose exec app bash` fails
**Diagnostic**:
```bash
docker compose ps app
```
**Solutions**:
**A) Container Not Running**
```bash
make up
```
**B) Use Different Shell**
```bash
docker compose exec app sh
```
## Complete Reset Procedure
If all else fails, completely reset the environment:
```bash
# 1. Stop and remove everything
docker compose down -v
# 2. Remove dangling images
docker system prune -f
# 3. Rebuild from scratch
export USER_ID=$(id -u) && export GROUP_ID=$(id -g)
docker compose up -d --build
# 4. Reinstall dependencies
make install
# 5. Import database schema
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
# 6. Verify
docker compose ps
curl http://localhost:8000
```
## Diagnostic Command Checklist
Run these commands to gather diagnostic information:
```bash
# 1. Container status
docker compose ps
# 2. Container logs
docker compose logs --tail=50
# 3. Docker version
docker --version
docker compose version
# 4. Port availability
sudo lsof -i :8000
sudo lsof -i :8080
sudo lsof -i :3306
# 5. Disk space
df -h
# 6. Docker disk usage
docker system df
# 7. Network connectivity
docker compose exec app ping -c 3 db
# 8. Environment variables
docker compose exec app env | grep DB_
# 9. File permissions
docker compose exec app ls -la /var/www/html/storage
# 10. Test database connection
docker compose exec app mysql -h db -u foundation_user -pfoundation_password foundation -e "SELECT 1;"
```
## Prevention Best Practices
1. **Regular Cleanup**
```bash
docker system prune -f
```
2. **Monitor Logs**
```bash
docker compose logs -f
```
3. **Use Make Commands**
- Prefer `make up` over direct `docker compose` commands
- Ensures consistent environment setup
4. **Keep Docker Updated**
```bash
# Check for updates
docker --version
```
5. **Document Environment**
- Note any custom ports or configurations
- Keep `.env` file up to date
## Getting Help
If issues persist:
1. **Collect Information**:
```bash
docker compose ps > debug-status.txt
docker compose logs > debug-logs.txt
docker compose config > debug-config.txt
```
2. **Check Docker Documentation**: https://docs.docker.com
3. **Review Project Issues**: Check if it's a known issue
4. **System Requirements**:
- Docker Engine 20.10+
- Docker Compose 2.0+
- At least 4GB RAM allocated to Docker
- 10GB free disk space
## Quick Reference
```bash
# Status and logs
docker compose ps
docker compose logs -f app
# Restart
docker compose restart app
docker compose restart db
# Full reset
docker compose down -v
make up
# Access shell
make shell
# Check ports
sudo lsof -i :8000
sudo lsof -i :8080
sudo lsof -i :3306
# View resource usage
docker stats
# Clean up
docker system prune -f
# Rebuild
make down
docker compose up -d --build
```

351
Claude.md Normal file
View file

@ -0,0 +1,351 @@
# Foundation Framework - Claude Context
## Project Overview
Foundation is a PHP framework built with Domain-Driven Design (DDD) principles, featuring clean architecture, modular design, and modern PHP 8+ capabilities. The framework emphasizes separation of concerns, testability, and maintainability.
## Technology Stack
- **PHP**: 8.1+
- **HTTP Framework**: Slim 4
- **Dependency Injection**: PHP-DI 7.0
- **Database**: MySQL 8.0 with PDO and Repository pattern
- **Logging**: Monolog 3.0
- **Environment Config**: phpdotenv
- **Development**: Docker + Docker Compose with Xdebug
## Architecture Principles
### Clean Architecture Layers
The framework follows strict layered architecture with clear dependency rules:
```
Domain (Pure business logic - No dependencies)
Application (Use cases - Depends on Domain only)
Infrastructure (External adapters - Depends on Application only)
```
**Layer Dependency Rules:**
- **Domain Layer**: Completely independent, no external dependencies
- **Application Layer**: Can depend on Domain and itself only
- **Infrastructure Layer**: Can depend on Application and itself only
### Module Structure
Each module follows this structure:
```
src/Modules/{ModuleName}/
├── Domain/ # Pure business logic
│ ├── {Entity}.php # Entities with identity
│ ├── {ValueObject}.php # Immutable value objects
│ └── {Repository}Interface.php # Repository contracts
├── Application/ # Use cases and orchestration
│ └── {UseCase}/
│ └── {UseCase}.php
└── Infrastructure/ # External implementations
├── Api/ # API controllers
├── Web/ # Web controllers
└── Database/ # Repository implementations
├── {Repository}.php
├── Commands/
└── Queries/
```
### Core Framework Structure
```
src/Core/
├── Application/ # Application orchestration
│ ├── Application.php # Main application class
│ ├── Kernel/HttpKernel.php # HTTP request handling
│ ├── DependencyInjection/ # DI container setup
│ ├── Bootstrapper/ # Application initialization
│ └── ServiceProvider/ # Service registration abstractions
├── ErrorHandling/ # Error handling and responses
├── Logging/ # Logging infrastructure
├── Session/ # Session management
└── Cache/ # Caching interfaces
```
## Key Concepts
### 1. Service Providers
Service Providers register services and bootstrap module-specific functionality:
- Register services in the DI container
- Bootstrap module-specific functionality
- Register HTTP routes via attribute scanning
- Auto-discovered by `ModuleLoader` from `src/Modules/*/` directories
### 2. Bootstrappers
Framework components that set up the application before handling requests:
- `ConfigInitializer` - Environment configuration
- `DatabaseInitializer` - Database connections
- `SessionInitializer` - Session management
- `ModuleLoader` - Auto-discovers and loads module service providers
### 3. Dependency Injection Container
The framework uses `InflectableContainer`, a wrapper around PHP-DI with enhanced features:
- **Container Inflection**: Automatic method invocation during object resolution
- **Smart Parameter Resolution**: Intelligent detection of class names vs static values
- **Simplified Registration**: Clean syntax for dependency declaration
**Example:**
```php
// Basic registration
$container->register(ServiceClass::class, [DependencyClass::class]);
// Interface binding
$container->bind(InterfaceClass::class, ImplementationClass::class, [Dep1::class]);
// Container inflection (automatic method calls)
$container->inflect(UnitOfWork::class)
->invokeMethod('registerPersister', [ActivityPersister::class]);
```
### 4. Attribute-Based Routing
Controllers use PHP 8+ attributes for route definitions:
- Controllers must implement `ControllerInterface`
- Routes automatically discovered during controller registration
- Available attributes: `#[Get]`, `#[Post]`, `#[Put]`, `#[Delete]`, `#[Route]`, `#[Group]`
**Example:**
```php
#[Group('/api/v1/users')]
class UserController implements ControllerInterface
{
#[Get('')]
public function index(): ResponseInterface { }
#[Get('/{id}')]
public function show(string $id): ResponseInterface { }
#[Post('', middleware: [AuthMiddleware::class])]
public function create(): ResponseInterface { }
}
```
### 5. Unit of Work Pattern
Manages database transactions and entity persistence:
- **Entity Persisters**: Handle database operations for specific entity types
- **Registration**: Via container inflection
- **Transactional**: All operations executed in single transaction
### 6. CQRS Separation
Commands (write operations) and Queries (read operations) are separated:
- Commands in `Infrastructure/Database/Commands/`
- Queries in `Infrastructure/Database/Queries/`
## Development Workflow
### Docker Environment
See skill: `/docker-setup` for detailed instructions.
All development happens in Docker containers with PHP 8.1, MySQL 8.0, and phpMyAdmin. Use `make up` to start the environment and `make install` to install dependencies.
### Testing
See skill: `/run-tests` for detailed instructions.
Comprehensive testing suite with PHPUnit supporting unit tests, integration tests, and coverage reports. Use `make test` to run all tests.
### Code Quality
See skill: `/static-analysis` for detailed instructions.
Static analysis with PHPStan and Deptrac to enforce type safety and architectural boundaries. Use `make static-analysis` to run both tools.
## Important Patterns
### Adding New Modules
See skill: `/create-module` for detailed instructions.
Create modules following DDD principles with Domain, Application, and Infrastructure layers. The ModuleLoader automatically discovers service providers in `src/Modules/*/`.
### Creating Service Provider
```php
class MyModuleServiceProvider extends ServiceProvider
{
public function register(InflectableContainer $container): void
{
// Register services
$container->register(MyController::class, [MyService::class]);
// Bind interfaces
$container->bind(MyRepositoryInterface::class, MyRepository::class);
}
}
```
### Repository Implementation
Repositories use Commands/Queries pattern:
```php
class MyRepository implements MyRepositoryInterface
{
public function __construct(
private FetchAllQuery $fetchAll,
private SaveCommand $save,
private UnitOfWorkInterface $unitOfWork
) {}
public function save(Entity $entity): void
{
$this->unitOfWork->registerNew($entity);
$this->unitOfWork->commit();
}
}
```
## Authentication System
Two authentication modes available:
- **Session-based**: Traditional session authentication
- **JWT-based**: Token-based authentication with firebase/php-jwt
Configured via `AUTH_TYPE` environment variable.
## Internationalization
Multi-language support using Symfony Translation:
- Default locale configurable via environment
- YAML translation files
- Module-specific translations supported
## Environment Variables
Key environment variables (see `.env.example`):
```env
# Database
DB_HOST=db
DB_PORT=3306
DB_DATABASE=foundation
DB_USERNAME=foundation_user
DB_PASSWORD=foundation_password
# Authentication
AUTH_TYPE=session
JWT_SECRET=your-secret-key
JWT_ACCESS_TOKEN_TTL=900
# Locale
APP_LOCALE=en
APP_SUPPORTED_LOCALES=en,de,fr
```
## Debugging
See skill: `/debug-setup` for detailed instructions.
Xdebug is pre-configured in the Docker environment for PHPStorm and VS Code. Debug sessions connect on port 9003 with automatic path mapping to `/var/www/html`.
## Documentation
Complete documentation available in `./documentation/`:
- `application-core.md` - Framework architecture overview
- `application-layers.md` - Layer dependency rules
- `attribute-routing.md` - Route attribute system
- `dependency-injection.md` - DI container guide
- `docker-setup.md` - Docker environment details
- `unit-of-work.md` - Unit of Work pattern
- `authentication.md` - Authentication implementation
- `internationalization.md` - i18n setup
## Common Commands Reference
**Docker:**
```bash
make up # Start Docker environment
make down # Stop Docker environment
make shell # Access container shell
```
**Dependencies:**
```bash
make install # Install composer dependencies
make dump-autoload # Refresh autoload files
```
**Testing:**
```bash
make test # Run all tests
make test-unit # Run unit tests
make test-coverage # Generate coverage report
```
**Quality:**
```bash
make phpstan # Static analysis
make deptrac # Layer analysis
make rector # Code quality preview
```
**Database:**
See skill: `/database-operations` for detailed instructions.
```bash
# Import schema
docker compose exec -T db mysql -u foundation_user -pfoundation_password foundation < database/schema.sql
```
## Best Practices
1. **Always respect layer boundaries** - Domain must remain pure
2. **Use value objects** for primitive obsession
3. **Keep controllers thin** - Delegate to application services
4. **Use repository interfaces** in Domain layer
5. **Implement CQRS** - Separate read and write operations
6. **Write tests** - Unit tests for domain, integration for infrastructure
7. **Use attributes for routes** - Don't register routes manually
8. **Follow PSR standards** - PSR-4 autoloading, PSR-7 HTTP messages
9. **Document public APIs** - Clear docblocks for interfaces
10. **Use type hints** - Leverage PHP 8.1+ type system
## Troubleshooting
### Docker Issues
See skill: `/troubleshoot-docker` for detailed diagnostic steps and solutions.
Common issues include port conflicts (8000, 8080, 3306), permission errors, and container startup failures. Use `docker compose ps` and `docker compose logs` to diagnose problems.
### Database Connection Issues
- Verify database container is running: `docker compose ps`
- Check environment variables in `.env`
- Ensure database schema is imported
### Routing Issues
- Verify controller implements `ControllerInterface`
- Check route attributes syntax
- Ensure controller is registered in service provider
### Autoloading Issues
- Run `make dump-autoload` after adding new classes
- Verify PSR-4 namespace matches directory structure