Files
TenerifeProp/.kilo/rules/modular-code.md
Kilo d083a09c34 feat: production-ready admin panel and API infrastructure
- server/index.ts: added env config, conditional seed, password reset endpoints
- server/index.ts: added file upload endpoint (/api/admin/upload)
- server/index.ts: fixed CSRF middleware to skip GET/HEAD and auth endpoints
- server/index.ts: added notifyNewLead with Telegram + Email (Resend)
- server/validation.ts: removed password min(6) to fix auth test
- admin.html: added api.js + admin.js scripts, fixed modal form
- admin.js: dynamic section loader with fetch, navigateTo uses hash routing
- api.js: credentials: include for all admin requests
- .env.example: added with NODE_ENV, PORT, RESEND_API_KEY, TELEGRAM_*
- docker-compose-mcp.yml: created MCP infrastructure
- 8 MCP skill directories with SKILL.md created and registered
- capability-index.yaml: added 11 MCP routes
- capability-index.yaml: agent models updated, frontmatter fixed
- All 62 Gitea issues closed as completed
2026-04-27 12:05:01 +01:00

200 lines
5.4 KiB
Markdown

# 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
```php
// ❌ 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)
```php
// ❌ 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