Files
APAW/.kilo/rules/modular-code.md
¨NW¨ b46a1a20a8 feat: add PHP development stack, atomic tasks, modular code rules, agent monitoring, fix target project detection
7 evolutionary tasks implemented:

1. PHP web development: php-developer agent + 6 skills (Laravel, Symfony, WordPress, security, testing, modular architecture) + 2 pipeline commands (/laravel, /wordpress)

2. Atomic task decomposition: 1 action = 1 task rule, task sizing guide, decomposition protocol for orchestrator, token budgets per complexity

3. Modular code rules: max 100 lines/file, max 30 lines/function, service/repository patterns, cross-module communication via events only

4. Gitea-centric workflow: mandatory issue creation before work, research with links, progress checkboxes, screenshots on test, git history as knowledge base

5. Fix: target project auto-detection — removed all hardcoded UniqueSoft/APAW from API calls, added get_target_repo() via git remote, GITEA_TARGET_REPO env override

6. Agent execution monitoring: agent-executions.jsonl logging, agent-stats.ts statistics script, required fields per invocation, Gitea comment includes duration/tokens

7. Token optimization: 1 action = 1 task principle, token budgets by task type, routing matrix, no scope creep, skip unnecessary pipeline steps
2026-04-18 23:43:04 +01:00

5.4 KiB

Modular Code Rules

CRITICAL: Never write giant monolithic files. Split code into modules, libraries, and microservice-ready components.

Problem

Agents write enormous single files that are hard to review, test, debug, and maintain. No clear boundaries between features.

Core Principles

  1. Maximum file size: 100 lines per file (excluding tests and migrations)
  2. Maximum function/method size: 30 lines
  3. Maximum class size: 5 public methods
  4. One responsibility per file: A file does ONE thing

Module Structure (Mandatory)

Every feature must be organized as an independent module:

{feature}/
├── Controllers/     # HTTP request handling (thin)
├── Services/        # Business logic (fat)
├── Repositories/    # Data access (abstracted)
├── Models/          # Data definitions
├── Routes/           # Route definitions
├── Events/           # Events this module emits
├── Listeners/        # Events this module handles
├── Jobs/             # Async work this module performs
├── Requests/         # Input validation (not in controller)
├── Resources/        # Output transformation (not raw model)
├── Exceptions/       # Module-specific exceptions
├── Tests/            # Module-specific tests
└── ModuleServiceProvider.php  # Module registration

Service Layer Rules

// ❌ BAD: Business logic in controller
class ProductController
{
    public function store(Request $request)
    {
        $product = Product::create($request->all());
        Cache::forget('products');
        event(new ProductCreated($product));
        Mail::to($product->vendor)->send(new NewProduct($product));
        return response()->json($product);
    }
}

// ✅ GOOD: Business logic in service
class ProductController
{
    public function __construct(private ProductService $service) {}
    
    public function store(ProductStoreRequest $request): JsonResponse
    {
        $product = $this->service->create($request->validated());
        return response()->json(new ProductResource($product), 201);
    }
}

class ProductService
{
    public function create(array $data): Product
    {
        $product = $this->repository->create($data);
        $this->clearCache();
        ProductCreated::dispatch($product);
        $this->notifyVendor($product);
        return $product;
    }
}

Repository Pattern (Mandatory for Data Access)

// ❌ BAD: Query in controller or service
$products = Product::where('active', true)->paginate(20);

// ✅ GOOD: Query in repository
interface ProductRepositoryInterface
{
    public function listActive(int $perPage = 20): LengthAwarePaginator;
}

class ProductRepository implements ProductRepositoryInterface
{
    public function __construct(private Product $model) {}
    
    public function listActive(int $perPage = 20): LengthAwarePaginator
    {
        return $this->model->query()
            ->where('is_active', true)
            ->orderBy('created_at', 'desc')
            ->paginate($perPage);
    }
}

Cross-Module Communication

Modules MUST NOT import models or repositories from other modules.

❌ Product module imports Order model directly
❌ Order module calls ProductRepository directly

✅ Product module dispatches ProductCreated event
✅ Order module listens to ProductCreated event
✅ Module boundaries enforced via interfaces

Microservice Readiness

Every module must be extractable as an independent service:

  1. Own database migrations: Module manages its own tables
  2. Own routes: Module registers its own routes
  3. Own config: Module has its own configuration
  4. Own tests: Module tests run independently
  5. Interface contracts: Module exposes interfaces, not implementations

File Splitting Rules

When a file exceeds 100 lines:

Original: ProductController.php (250 lines)
   ↓ Split into:
ProductController.php        # index, show (thin delegates)
ProductStoreController.php   # store endpoint (thin delegates)
ProductUpdateController.php  # update endpoint (thin delegates)
ProductService.php           # business logic (called by all)

When a service exceeds 5 methods:

Original: ProductService.php (8 methods)
   ↓ Split into:
ProductCrudService.php      # create, update, delete
ProductSearchService.php    # list, search, filter
ProductPricingService.php   # calculatePrice, applyDiscount

Language-Specific Module Patterns

Node.js

src/modules/product/
├── routes.js
├── controller.js
├── service.js
├── repository.js
├── model.js
├── validators.js
└── __tests__/

Go

internal/product/
├── handler.go
├── service.go
├── repository.go
├── model.go
└── handler_test.go

Flutter/Dart

lib/features/product/
├── data/
│   ├── repositories/
│   └── models/
├── domain/
│   ├── entities/
│   └── usecases/
└── presentation/
    ├── pages/
    ├── widgets/
    └── providers/

Checklist

  • Every file under 100 lines
  • Every function under 30 lines
  • Every class under 5 public methods
  • Features organized as modules
  • Service layer contains business logic
  • Repository layer abstracts data access
  • Controllers are thin (5-10 lines per method)
  • Cross-module communication via events
  • Each module testable independently
  • Each module extractable to microservice