home / skills / hoangnguyen0403 / agent-skills-standard / layer-based-clean-architecture

layer-based-clean-architecture skill

/skills/flutter/layer-based-clean-architecture

This skill enforces layer-based clean architecture and DDD in Flutter, guiding code structure, dependencies, and testing for robust apps.

npx playbooks add skill hoangnguyen0403/agent-skills-standard --skill layer-based-clean-architecture

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
2.1 KB
---
name: Flutter Layer-based Clean Architecture + DDD
description: Standards for separation of concerns, layer dependency rules, and DDD in Flutter.
metadata:
  labels: [architecture, clean-architecture, layers, ddd]
  triggers:
    files: ['lib/domain/**', 'lib/infrastructure/**', 'lib/application/**']
    keywords:
      [domain, infrastructure, application, presentation, layers, dto, mapper]
---

# Layer-Based Clean Architecture

## **Priority: P0 (CRITICAL)**

Standardized separation of concerns and dependency flow using DDD principles.

## Structure

```text
lib/
├── domain/ # Pure Dart: entities (@freezed), failures, repository interfaces
├── infrastructure/ # Implementation: DTOs, data sources, mappers, repo impls
├── application/ # Orchestration: BLoCs / Cubits
└── presentation/ # UI: Screens, reusable components
```

## Implementation Guidelines

- **Dependency Flow**: `Presentation -> Application -> Domain <- Infrastructure`. Dependencies point inward.
- **Pure Domain**: No Flutter (Material/Store) or Infrastructure (Dio/Hive) dependencies in `Domain`.
- **Functional Error Handling**: Repositories must return `Either<Failure, Success>`.
- **Always Map**: Infrastructure must map DTOs to Domain Entities; do not leak DTOs to UI.
- **Immutability**: Use `@freezed` for all entities and failures.
- **Logic Placement**: No business logic in UI; widgets only display state and emit events.
- **Inversion of Control**: Use `get_it` to inject repository implementations into BLoCs.

## Anti-Patterns

- **No DTOs in UI**: Never import a `.g.dart` or Data class directly in a Widget.
- **No Material in Domain**: Do not import `package:flutter/material.dart` in the `domain` layer.
- **No Shared Prefs in Repo**: Do not use `shared_preferences` directly in a Repository; use a Data Source.

## Reference & Examples

For full implementation templates and DTO-to-Domain mapping examples:
See [references/REFERENCE.md](references/REFERENCE.md).

## Related Topics

feature-based-clean-architecture | bloc-state-management | dependency-injection | error-handling

Overview

This skill codifies a layer-based Clean Architecture for Flutter projects using Domain-Driven Design (DDD) principles. It prescribes folder layout, dependency flow, and concrete rules to keep domain code pure, ensure clear boundaries, and prevent infrastructure leakage into UI. The goal is predictable, testable code with consistent error handling and mapping rules.

How this skill works

The skill enforces a four-layer layout: presentation, application, domain, and infrastructure. Dependencies flow inward: Presentation -> Application -> Domain <- Infrastructure. Repositories return functional results (Either<Failure, Success>), infrastructure maps DTOs to immutable domain entities (@freezed), and dependency injection (get_it) wires implementations into BLoCs/Cubits.

When to use it

  • Building medium to large Flutter apps where separation of concerns and testability matter.
  • When you need predictable dependency rules to avoid UI or platform leakage into core logic.
  • Implementing business-critical features that require robust error handling and clear mapping.
  • When multiple teams or contributors must follow the same architecture standards.
  • Migrating legacy code toward a more maintainable, domain-centric structure.

Best practices

  • Keep domain layer pure Dart: no Flutter widgets, material imports, or platform packages.
  • Always map DTOs to domain entities in infrastructure; never pass DTOs to presentation.
  • Use @freezed for entities and failures to guarantee immutability and pattern matching.
  • Return Either<Failure, Success> from repository interfaces for functional error handling.
  • Place orchestration and state management (BLoCs/Cubits) in application layer; UI only renders state and emits events.
  • Register implementations with get_it and inject them into BLoCs to follow inversion of control.

Example use cases

  • Implementing a user authentication flow: DTOs from network mapped to User entity, auth logic in application, UI reacts to states only.
  • Building offline-first features: data sources in infrastructure handle caching; domain exposes repository interfaces.
  • Refactoring large screens: extract business logic from widgets into application and domain layers.
  • Creating reusable feature modules: each feature follows the same folder layout and dependency rules for consistency.

FAQ

Can domain layer use any external package?

Keep domain dependencies minimal and pure Dart only; avoid Flutter, HTTP clients, or local storage packages in domain.

Where should caching via shared_preferences live?

Implement caching in an infrastructure data source; repository implementations can delegate to that data source rather than using shared_preferences directly.