Agent skill
nette-architecture
Provides Nette application architecture guidelines. Use when working with presenters, modules, directory structure, Core vs Model decisions, or Nette MVC patterns.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/design/nette-architecture-nette-claude-code
SKILL.md
For new project skeleton, see skeleton.md.
Backend Architecture
- The project requires PHP 8.3+, Nette 3.2, Latte 3.1
Key Framework Features
- Presenters: Controllers that handle HTTP requests in Nette
- Latte: Templating engine used for views
- Dependency Injection: Service management through Nette's DI container
- Router: URL routing through
RouterFactory
Directory Structure
The application follows domain-driven organization with preference for flatter structure:
- App: The main application namespace (
App\)- Bootstrap: Application initialization and configuration
- Core: Infrastructure concerns (routing, etc.)
- Entity: All database entities in single namespace
- Model: Business logic services organized by domain
- Presentation: UI layer organized by modules
- Tasks: Command-line executable tasks
Evolution Strategy
Start minimal → Grow organically → Refactor when painful
Start with flat structure - create subdirectories only when you have 5+ related files or clear implementation variants. Don't architect for theoretical future complexity. Address actual complexity when it emerges with clear user needs driving structural decisions.
Configuration
- config/common.neon: Main application configuration
- config/services.neon: Service definitions and auto-wiring configuration
Core vs Model Decision Matrix
Use Core/ for:
- Technology-agnostic infrastructure (MyExplorer, RouterFactory, QueueMailer)
- External service integrations (SentryLogger, AI/, GoogleSearch/)
- Framework extensions and utilities
- Code that could be moved to another project unchanged
Use Model/ for:
- Business domain logic (CatalogService, CustomerService, OrderService)
- Domain-specific operations and rules
- Entity-specific processing logic
- Code that knows about your business concepts (products, orders, customers)
Why flat: Entities often cross domain boundaries. ProductRow might be used in catalog, orders, and inventory contexts.
Model Layer Principles
app/Model/
├── CatalogService.php ← Main domain services at root
├── CustomerService.php
├── OrderService.php
├── mails/ ← Email templates (specialized assets)
├── Payment/ ← Implementation variants
│ ├── CardOnlinePayment.php
│ ├── BankTransferPayment.php
│ └── CashPayment.php
└── exceptions.php ← Domain exceptions
Service placement rules:
- Main domain coordinator services directly in Model/
- Implementation variants get subdirectories when 3+ implementations exist
- Specialized assets (templates, exceptions) in focused locations
Module Structure
app/Presentation/
├── Accessory/ ← UI shared across entire application
│ ├── LatteExtension.php
│ └── TemplateFilters.php
├── Admin/
│ ├── BasePresenter.php ← Admin-specific functionality
│ ├── Auth/ ← Authentication
│ ├── Catalog/ ← Product management
│ │ ├── Brand/
│ │ ├── List/ ← Overview/utility presenters
│ │ └── Product/
│ └── Fulfill/ ← Order processing
└── Front/
├── Customer/
└── Listing/
Keep presenters flat until complexity demands structure:
# Start simple
Dashboard/DashboardPresenter.php
# Grow when needed
Admin/Catalog/Product/ProductPresenter.php
Admin/Catalog/Brand/BrandPresenter.php
Admin/Catalog/List/ListPresenter.php
Create nested structure when:
- Single functional area has 4+ presenters
- Clear sub-domains emerge (Product management, Order fulfillment)
- Shared logic between related presenters
Base Presenter Strategy
Create BasePresenter for each major module only when needed:
Admin\BasePresenter- authentication checks, admin-specific setup- Contains common
beforeRender(), authentication logic, shared template variables
Avoid deep inheritance - prefer composition over inheritance chains deeper than BasePresenter → SpecificPresenter.
Accessory Placement Decision Tree
Use Presentation/Accessory/ for:
- Components used across multiple modules (navigation, forms)
- Latte extensions and template filters
- Shared template functionality
Use Module/Accessory/ for:
- Components specific to that module but used by multiple presenters
- Module-specific template helpers
Use Presenter directory for:
- Components used only by that presenter
- Presenter-specific forms and controls
When to Create New Module
Create module when:
- You have 5+ related presenters
- Functionality has distinct user base (Admin vs Front vs Api)
- Different authentication/authorization requirements
- Separate URL structure patterns
Avoid modules for:
- Single presenter with single purpose
- Artificial separation without clear user/functional boundaries
Tasks and Command Organization
app/Tasks/
├── Maintenance/ ← Cleanup, optimization
├── Integration/ ← External data sync
└── Scheduled/ ← Recurring operations
Task responsibility boundaries:
- Tasks handle execution context (CLI arguments, error handling, scheduling)
- Business logic stays in Model services
- Tasks coordinate, services execute
Anti-Patterns to Avoid
Don't create directories prematurely - wait until you have actual complexity, not anticipated complexity.
Don't separate by technical layer - avoid Services/, Repositories/, Controllers/ separation in favor of domain organization.
Don't create deep hierarchies - prefer descriptive names over nested structure (OrderFulfillmentService vs Fulfill/Order/Service).
Don't duplicate Base presenter logic - use inheritance or traits instead of copying common functionality.
#[Requires] Attribute
Control access to presenter actions and signals:
use Nette\Application\Attributes\Requires;
class AdminPresenter extends BasePresenter
{
// Require AJAX only
#[Requires(ajax: true)]
public function handleDelete(int $id): void
{
}
// Require POST method
#[Requires(methods: 'POST')]
public function actionSave(): void
{
}
// Require specific methods
#[Requires(methods: ['GET', 'POST'])]
public function actionEdit(int $id): void
{
}
// Require forward (not direct access)
#[Requires(forward: true)]
public function actionConfirm(): void
{
}
// Combine requirements
#[Requires(ajax: true, methods: 'POST')]
public function handleUpdate(): void
{
}
}
Apply to entire presenter:
#[Requires(ajax: true)]
class ApiPresenter extends BasePresenter
{
// All actions require AJAX
}
Passing Settings to Presenters
Via DI container (recommended):
# config/services.neon
services:
- App\Presentation\Admin\ProductPresenter(itemsPerPage: 20)
class ProductPresenter extends BasePresenter
{
public function __construct(
private int $itemsPerPage,
private ProductFacade $facade,
) {}
}
Via parameters:
# config/common.neon
parameters:
pagination:
itemsPerPage: 20
maxItems: 1000
# config/services.neon
services:
- App\Presentation\ProductPresenter(
itemsPerPage: %pagination.itemsPerPage%
)
Via base presenter:
abstract class BasePresenter extends Nette\Application\UI\Presenter
{
public int $itemsPerPage = 20;
public function injectSettings(Settings $settings): void
{
$this->itemsPerPage = $settings->get('pagination.itemsPerPage', 20);
}
}
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?