Repository files navigation

Architecture

This document describes how backend code is structured and how the main parts interact.

It defines a single, shared approach used by the team to keep systems easy to understand, easy to change, and consistent over time.

The approach is inspired by Clean Architecture and DDD, but intentionally simplified to avoid unnecessary layers and overhead.
The goal is to provide one clear way of thinking and coding as a team.

The initial design and consolidation of these ideas were proposed by Vinicius Rangel.
If questions arise about decisions or trade-offs, they can be discussed directly.


Table of Contents

  1. Architectural Approach
  2. Core Concepts
  3. Interactions
  4. Testing
  5. Examples
  6. Frameworks
  7. IA

Architectural Approach

This architecture borrows the most valuable ideas from Clean Architecture while reducing conceptual fragmentation.

In classic Clean Architecture, concepts such as Entity, Model, Use Case, and Interactor are often separated.
In practice, this separation can lead to duplicated responsibilities, higher cognitive load, and extra maintenance cost.

This approach favors:

  • A small number of well-defined concepts
  • Clear ownership of behavior
  • Predictable interaction between layers

The intention is consistency and maintainability, not theoretical purity.


About Entities in This Architecture

In traditional Clean Architecture:

  • Entities represent enterprise business rules
  • Models represent persistence concerns

In this architecture, these concepts are merged into a single Entity.

An Entity:

  • Represents a domain concept
  • Holds state and behavior
  • May include persistence mapping
  • Is not treated only as a storage structure

This removes ambiguity and encourages a behavior-first mindset, rather than a database-first one.

When external references define entities differently, the definition in this document represents the standard used by the team.


Core Concepts

Entity

Represents a domain object with state and behavior.

  • Encapsulates business rules related to itself
  • Controls how its state changes
  • Independent of application flow

→ Details and examples: entities.md


Use Case

Represents an application action or intent.

  • Coordinates entities
  • Defines application flow
  • Receives input and produces an outcome

→ Details and examples: use-cases.md


Service

Represents a pluggable external or third-party capability.

Services are used whenever something is integrated into the system, such as:

  • External APIs
  • Messaging systems
  • Payment providers
  • File storage
  • Any replaceable external tool

Characteristics:

  • Always defined by an interface
  • Implementation can be swapped without affecting core logic
  • Executes a capability but does not orchestrate application flow

→ Details and examples: services.md


Repository

Represents access to persisted entities.

  • Loads and saves entities
  • Hides persistence details
  • Does not contain business rules

→ Details and examples: repositories.md


Interactions

A common interaction flow looks like this:

Controller → Use Case → Entity
↓
Service / Repository

This flow keeps responsibilities explicit and dependencies predictable.

→ Interaction patterns and variations: interactions.md


Testing

Testing in this architecture focuses primarily on unit tests.

Unit tests provide fast feedback, protect behavior, and help keep responsibilities clear across entities and use cases.

The goal of testing is confidence, not coverage metrics or test quantity.


Unit Tests

Unit tests are the main and preferred form of testing.

They focus on:

  • Entity behavior
  • Use case execution
  • Clear inputs and outputs
  • State transitions and invariants

Well-written unit tests should:

  • Run fast
  • Avoid infrastructure
  • Be easy to read
  • Be easy to maintain

What We Unit Test

Entities

  • Test behavior through public methods
  • Validate state changes
  • Ensure invariants are enforced

Use Cases

  • Test execution flow
  • Validate interactions with entities
  • Use mocks or fakes for repositories and services

What We Avoid in Unit Tests

Unit tests should not:

  • Boot the framework
  • Use a real database
  • Use the service container
  • Depend on external systems

These concerns belong to other types of tests and are intentionally out of scope here.


About TDD

Test-Driven Development (TDD) is encouraged but not required.

When used, TDD can help:

  • Clarify intent before implementation
  • Drive better APIs for entities and use cases
  • Keep code focused on behavior

TDD is a technique, not a rule.

The important part is that behavior is testable and tested, regardless of the order in which code and tests are written.


Testing as Design Feedback

Tests are not only a safety net, but also a design tool.

If a piece of code is impossible to unit test, it is usually a sign of bad design.

Common indicators include:

  • Too many responsibilities
  • Hidden dependencies
  • Tight coupling to infrastructure
  • Unclear boundaries

Improving the design usually improves testability as well.


Summary

  • Unit tests are the primary testing strategy
  • Entities and use cases are the main focus
  • Infrastructure is excluded from unit tests
  • TDD is optional, clarity is not

Testing exists to support maintainability and confidence — not to slow development down.


Examples

Examples illustrate common situations and design decisions.

They are intentionally small and focused, serving as reference rather than templates.

→ Browse examples: examples/README.md


Frameworks

Core architectural concepts remain the same across frameworks.
This section documents how those concepts map to specific frameworks.


Framework: Symfony

Symfony-specific guidance focused on applying entities, use cases, services, and repositories within the framework.

Topics include:

  • Controllers as entry points
  • Dependency injection and the service container
  • Doctrine usage in relation to entities
  • Console commands and background processes

→ Symfony architecture guide: frameworks/symfony/README.md


AI Assistance (Claude)

This repository includes an AI context file used to keep AI-assisted development aligned with our architectural patterns.

The file is located at:

claude.md

How to use it

When using Claude (or any LLM) to generate code or discuss architecture:

  1. Open claude.md
  2. Copy the entire content
  3. Paste it into Claude as context / system instructions
  4. Then ask your question or request code

This ensures AI-generated suggestions follow the same rules and boundaries used by the team (Entity, Use Case, Service, Repository).

If AI suggestions conflict with the architecture, the rules in claude.md take precedence.


About

This documentation describes the core architectural concepts used across backend systems and how they interact.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

Architecture

This document describes how backend code is structured and how the main parts interact.

It defines a single, shared approach used by the team to keep systems easy to understand, easy to change, and consistent over time.

The approach is inspired by Clean Architecture and DDD, but intentionally simplified to avoid unnecessary layers and overhead.
The goal is to provide one clear way of thinking and coding as a team.

The initial design and consolidation of these ideas were proposed by Vinicius Rangel.
If questions arise about decisions or trade-offs, they can be discussed directly.


Table of Contents

  1. Architectural Approach
  2. Core Concepts
  3. Interactions
  4. Testing
  5. Examples
  6. Frameworks
  7. IA

Architectural Approach

This architecture borrows the most valuable ideas from Clean Architecture while reducing conceptual fragmentation.

In classic Clean Architecture, concepts such as Entity, Model, Use Case, and Interactor are often separated.
In practice, this separation can lead to duplicated responsibilities, higher cognitive load, and extra maintenance cost.

This approach favors:

  • A small number of well-defined concepts
  • Clear ownership of behavior
  • Predictable interaction between layers

The intention is consistency and maintainability, not theoretical purity.


About Entities in This Architecture

In traditional Clean Architecture:

  • Entities represent enterprise business rules
  • Models represent persistence concerns

In this architecture, these concepts are merged into a single Entity.

An Entity:

  • Represents a domain concept
  • Holds state and behavior
  • May include persistence mapping
  • Is not treated only as a storage structure

This removes ambiguity and encourages a behavior-first mindset, rather than a database-first one.

When external references define entities differently, the definition in this document represents the standard used by the team.


Core Concepts

Entity

Represents a domain object with state and behavior.

  • Encapsulates business rules related to itself
  • Controls how its state changes
  • Independent of application flow

→ Details and examples: entities.md


Use Case

Represents an application action or intent.

  • Coordinates entities
  • Defines application flow
  • Receives input and produces an outcome

→ Details and examples: use-cases.md


Service

Represents a pluggable external or third-party capability.

Services are used whenever something is integrated into the system, such as:

  • External APIs
  • Messaging systems
  • Payment providers
  • File storage
  • Any replaceable external tool

Characteristics:

  • Always defined by an interface
  • Implementation can be swapped without affecting core logic
  • Executes a capability but does not orchestrate application flow

→ Details and examples: services.md


Repository

Represents access to persisted entities.

  • Loads and saves entities
  • Hides persistence details
  • Does not contain business rules

→ Details and examples: repositories.md


Interactions

A common interaction flow looks like this:

Controller → Use Case → Entity
↓
Service / Repository

This flow keeps responsibilities explicit and dependencies predictable.

→ Interaction patterns and variations: interactions.md


Testing

Testing in this architecture focuses primarily on unit tests.

Unit tests provide fast feedback, protect behavior, and help keep responsibilities clear across entities and use cases.

The goal of testing is confidence, not coverage metrics or test quantity.


Unit Tests

Unit tests are the main and preferred form of testing.

They focus on:

  • Entity behavior
  • Use case execution
  • Clear inputs and outputs
  • State transitions and invariants

Well-written unit tests should:

  • Run fast
  • Avoid infrastructure
  • Be easy to read
  • Be easy to maintain

What We Unit Test

Entities

  • Test behavior through public methods
  • Validate state changes
  • Ensure invariants are enforced

Use Cases

  • Test execution flow
  • Validate interactions with entities
  • Use mocks or fakes for repositories and services

What We Avoid in Unit Tests

Unit tests should not:

  • Boot the framework
  • Use a real database
  • Use the service container
  • Depend on external systems

These concerns belong to other types of tests and are intentionally out of scope here.


About TDD

Test-Driven Development (TDD) is encouraged but not required.

When used, TDD can help:

  • Clarify intent before implementation
  • Drive better APIs for entities and use cases
  • Keep code focused on behavior

TDD is a technique, not a rule.

The important part is that behavior is testable and tested, regardless of the order in which code and tests are written.


Testing as Design Feedback

Tests are not only a safety net, but also a design tool.

If a piece of code is impossible to unit test, it is usually a sign of bad design.

Common indicators include:

  • Too many responsibilities
  • Hidden dependencies
  • Tight coupling to infrastructure
  • Unclear boundaries

Improving the design usually improves testability as well.


Summary

  • Unit tests are the primary testing strategy
  • Entities and use cases are the main focus
  • Infrastructure is excluded from unit tests
  • TDD is optional, clarity is not

Testing exists to support maintainability and confidence — not to slow development down.


Examples

Examples illustrate common situations and design decisions.

They are intentionally small and focused, serving as reference rather than templates.

→ Browse examples: examples/README.md


Frameworks

Core architectural concepts remain the same across frameworks.
This section documents how those concepts map to specific frameworks.


Framework: Symfony

Symfony-specific guidance focused on applying entities, use cases, services, and repositories within the framework.

Topics include:

  • Controllers as entry points
  • Dependency injection and the service container
  • Doctrine usage in relation to entities
  • Console commands and background processes

→ Symfony architecture guide: frameworks/symfony/README.md


AI Assistance (Claude)

This repository includes an AI context file used to keep AI-assisted development aligned with our architectural patterns.

The file is located at:

claude.md

How to use it

When using Claude (or any LLM) to generate code or discuss architecture:

  1. Open claude.md
  2. Copy the entire content
  3. Paste it into Claude as context / system instructions
  4. Then ask your question or request code

This ensures AI-generated suggestions follow the same rules and boundaries used by the team (Entity, Use Case, Service, Repository).

If AI suggestions conflict with the architecture, the rules in claude.md take precedence.


About

This documentation describes the core architectural concepts used across backend systems and how they interact.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Architecture

This document describes how backend code is structured and how the main parts interact.

It defines a single, shared approach used by the team to keep systems easy to understand, easy to change, and consistent over time.

The approach is inspired by Clean Architecture and DDD, but intentionally simplified to avoid unnecessary layers and overhead.
The goal is to provide one clear way of thinking and coding as a team.

The initial design and consolidation of these ideas were proposed by Vinicius Rangel.
If questions arise about decisions or trade-offs, they can be discussed directly.


Table of Contents

  1. Architectural Approach
  2. Core Concepts
  3. Interactions
  4. Testing
  5. Examples
  6. Frameworks
  7. IA

Architectural Approach

This architecture borrows the most valuable ideas from Clean Architecture while reducing conceptual fragmentation.

In classic Clean Architecture, concepts such as Entity, Model, Use Case, and Interactor are often separated.
In practice, this separation can lead to duplicated responsibilities, higher cognitive load, and extra maintenance cost.

This approach favors:

  • A small number of well-defined concepts
  • Clear ownership of behavior
  • Predictable interaction between layers

The intention is consistency and maintainability, not theoretical purity.


About Entities in This Architecture

In traditional Clean Architecture:

  • Entities represent enterprise business rules
  • Models represent persistence concerns

In this architecture, these concepts are merged into a single Entity.

An Entity:

  • Represents a domain concept
  • Holds state and behavior
  • May include persistence mapping
  • Is not treated only as a storage structure

This removes ambiguity and encourages a behavior-first mindset, rather than a database-first one.

When external references define entities differently, the definition in this document represents the standard used by the team.


Core Concepts

Entity

Represents a domain object with state and behavior.

  • Encapsulates business rules related to itself
  • Controls how its state changes
  • Independent of application flow

→ Details and examples: entities.md


Use Case

Represents an application action or intent.

  • Coordinates entities
  • Defines application flow
  • Receives input and produces an outcome

→ Details and examples: use-cases.md


Service

Represents a pluggable external or third-party capability.

Services are used whenever something is integrated into the system, such as:

  • External APIs
  • Messaging systems
  • Payment providers
  • File storage
  • Any replaceable external tool

Characteristics:

  • Always defined by an interface
  • Implementation can be swapped without affecting core logic
  • Executes a capability but does not orchestrate application flow

→ Details and examples: services.md


Repository

Represents access to persisted entities.

  • Loads and saves entities
  • Hides persistence details
  • Does not contain business rules

→ Details and examples: repositories.md


Interactions

A common interaction flow looks like this:

Controller → Use Case → Entity
↓
Service / Repository

This flow keeps responsibilities explicit and dependencies predictable.

→ Interaction patterns and variations: interactions.md


Testing

Testing in this architecture focuses primarily on unit tests.

Unit tests provide fast feedback, protect behavior, and help keep responsibilities clear across entities and use cases.

The goal of testing is confidence, not coverage metrics or test quantity.


Unit Tests

Unit tests are the main and preferred form of testing.

They focus on:

  • Entity behavior
  • Use case execution
  • Clear inputs and outputs
  • State transitions and invariants

Well-written unit tests should:

  • Run fast
  • Avoid infrastructure
  • Be easy to read
  • Be easy to maintain

What We Unit Test

Entities

  • Test behavior through public methods
  • Validate state changes
  • Ensure invariants are enforced

Use Cases

  • Test execution flow
  • Validate interactions with entities
  • Use mocks or fakes for repositories and services

What We Avoid in Unit Tests

Unit tests should not:

  • Boot the framework
  • Use a real database
  • Use the service container
  • Depend on external systems

These concerns belong to other types of tests and are intentionally out of scope here.


About TDD

Test-Driven Development (TDD) is encouraged but not required.

When used, TDD can help:

  • Clarify intent before implementation
  • Drive better APIs for entities and use cases
  • Keep code focused on behavior

TDD is a technique, not a rule.

The important part is that behavior is testable and tested, regardless of the order in which code and tests are written.


Testing as Design Feedback

Tests are not only a safety net, but also a design tool.

If a piece of code is impossible to unit test, it is usually a sign of bad design.

Common indicators include:

  • Too many responsibilities
  • Hidden dependencies
  • Tight coupling to infrastructure
  • Unclear boundaries

Improving the design usually improves testability as well.


Summary

  • Unit tests are the primary testing strategy
  • Entities and use cases are the main focus
  • Infrastructure is excluded from unit tests
  • TDD is optional, clarity is not

Testing exists to support maintainability and confidence — not to slow development down.


Examples

Examples illustrate common situations and design decisions.

They are intentionally small and focused, serving as reference rather than templates.

→ Browse examples: examples/README.md


Frameworks

Core architectural concepts remain the same across frameworks.
This section documents how those concepts map to specific frameworks.


Framework: Symfony

Symfony-specific guidance focused on applying entities, use cases, services, and repositories within the framework.

Topics include:

  • Controllers as entry points
  • Dependency injection and the service container
  • Doctrine usage in relation to entities
  • Console commands and background processes

→ Symfony architecture guide: frameworks/symfony/README.md


AI Assistance (Claude)

This repository includes an AI context file used to keep AI-assisted development aligned with our architectural patterns.

The file is located at:

claude.md

How to use it

When using Claude (or any LLM) to generate code or discuss architecture:

  1. Open claude.md
  2. Copy the entire content
  3. Paste it into Claude as context / system instructions
  4. Then ask your question or request code

This ensures AI-generated suggestions follow the same rules and boundaries used by the team (Entity, Use Case, Service, Repository).

If AI suggestions conflict with the architecture, the rules in claude.md take precedence.


About

This documentation describes the core architectural concepts used across backend systems and how they interact.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Architecture

This document describes how backend code is structured and how the main parts interact.

It defines a single, shared approach used by the team to keep systems easy to understand, easy to change, and consistent over time.

The approach is inspired by Clean Architecture and DDD, but intentionally simplified to avoid unnecessary layers and overhead.
The goal is to provide one clear way of thinking and coding as a team.

The initial design and consolidation of these ideas were proposed by Vinicius Rangel.
If questions arise about decisions or trade-offs, they can be discussed directly.


Table of Contents

  1. Architectural Approach
  2. Core Concepts
  3. Interactions
  4. Testing
  5. Examples
  6. Frameworks
  7. IA

Architectural Approach

This architecture borrows the most valuable ideas from Clean Architecture while reducing conceptual fragmentation.

In classic Clean Architecture, concepts such as Entity, Model, Use Case, and Interactor are often separated.
In practice, this separation can lead to duplicated responsibilities, higher cognitive load, and extra maintenance cost.

This approach favors:

  • A small number of well-defined concepts
  • Clear ownership of behavior
  • Predictable interaction between layers

The intention is consistency and maintainability, not theoretical purity.


About Entities in This Architecture

In traditional Clean Architecture:

  • Entities represent enterprise business rules
  • Models represent persistence concerns

In this architecture, these concepts are merged into a single Entity.

An Entity:

  • Represents a domain concept
  • Holds state and behavior
  • May include persistence mapping
  • Is not treated only as a storage structure

This removes ambiguity and encourages a behavior-first mindset, rather than a database-first one.

When external references define entities differently, the definition in this document represents the standard used by the team.


Core Concepts

Entity

Represents a domain object with state and behavior.

  • Encapsulates business rules related to itself
  • Controls how its state changes
  • Independent of application flow

→ Details and examples: entities.md


Use Case

Represents an application action or intent.

  • Coordinates entities
  • Defines application flow
  • Receives input and produces an outcome

→ Details and examples: use-cases.md


Service

Represents a pluggable external or third-party capability.

Services are used whenever something is integrated into the system, such as:

  • External APIs
  • Messaging systems
  • Payment providers
  • File storage
  • Any replaceable external tool

Characteristics:

  • Always defined by an interface
  • Implementation can be swapped without affecting core logic
  • Executes a capability but does not orchestrate application flow

→ Details and examples: services.md


Repository

Represents access to persisted entities.

  • Loads and saves entities
  • Hides persistence details
  • Does not contain business rules

→ Details and examples: repositories.md


Interactions

A common interaction flow looks like this:

Controller → Use Case → Entity
↓
Service / Repository

This flow keeps responsibilities explicit and dependencies predictable.

→ Interaction patterns and variations: interactions.md


Testing

Testing in this architecture focuses primarily on unit tests.

Unit tests provide fast feedback, protect behavior, and help keep responsibilities clear across entities and use cases.

The goal of testing is confidence, not coverage metrics or test quantity.


Unit Tests

Unit tests are the main and preferred form of testing.

They focus on:

  • Entity behavior
  • Use case execution
  • Clear inputs and outputs
  • State transitions and invariants

Well-written unit tests should:

  • Run fast
  • Avoid infrastructure
  • Be easy to read
  • Be easy to maintain

What We Unit Test

Entities

  • Test behavior through public methods
  • Validate state changes
  • Ensure invariants are enforced

Use Cases

  • Test execution flow
  • Validate interactions with entities
  • Use mocks or fakes for repositories and services

What We Avoid in Unit Tests

Unit tests should not:

  • Boot the framework
  • Use a real database
  • Use the service container
  • Depend on external systems

These concerns belong to other types of tests and are intentionally out of scope here.


About TDD

Test-Driven Development (TDD) is encouraged but not required.

When used, TDD can help:

  • Clarify intent before implementation
  • Drive better APIs for entities and use cases
  • Keep code focused on behavior

TDD is a technique, not a rule.

The important part is that behavior is testable and tested, regardless of the order in which code and tests are written.


Testing as Design Feedback

Tests are not only a safety net, but also a design tool.

If a piece of code is impossible to unit test, it is usually a sign of bad design.

Common indicators include:

  • Too many responsibilities
  • Hidden dependencies
  • Tight coupling to infrastructure
  • Unclear boundaries

Improving the design usually improves testability as well.


Summary

  • Unit tests are the primary testing strategy
  • Entities and use cases are the main focus
  • Infrastructure is excluded from unit tests
  • TDD is optional, clarity is not

Testing exists to support maintainability and confidence — not to slow development down.


Examples

Examples illustrate common situations and design decisions.

They are intentionally small and focused, serving as reference rather than templates.

→ Browse examples: examples/README.md


Frameworks

Core architectural concepts remain the same across frameworks.
This section documents how those concepts map to specific frameworks.


Framework: Symfony

Symfony-specific guidance focused on applying entities, use cases, services, and repositories within the framework.

Topics include:

  • Controllers as entry points
  • Dependency injection and the service container
  • Doctrine usage in relation to entities
  • Console commands and background processes

→ Symfony architecture guide: frameworks/symfony/README.md


AI Assistance (Claude)

This repository includes an AI context file used to keep AI-assisted development aligned with our architectural patterns.

The file is located at:

claude.md

How to use it

When using Claude (or any LLM) to generate code or discuss architecture:

  1. Open claude.md
  2. Copy the entire content
  3. Paste it into Claude as context / system instructions
  4. Then ask your question or request code

This ensures AI-generated suggestions follow the same rules and boundaries used by the team (Entity, Use Case, Service, Repository).

If AI suggestions conflict with the architecture, the rules in claude.md take precedence.


About

This documentation describes the core architectural concepts used across backend systems and how they interact.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

Architecture

This document describes how backend code is structured and how the main parts interact.

It defines a single, shared approach used by the team to keep systems easy to understand, easy to change, and consistent over time.

The approach is inspired by Clean Architecture and DDD, but intentionally simplified to avoid unnecessary layers and overhead.
The goal is to provide one clear way of thinking and coding as a team.

The initial design and consolidation of these ideas were proposed by Vinicius Rangel.
If questions arise about decisions or trade-offs, they can be discussed directly.


Table of Contents

  1. Architectural Approach
  2. Core Concepts
  3. Interactions
  4. Testing
  5. Examples
  6. Frameworks
  7. IA

Architectural Approach

This architecture borrows the most valuable ideas from Clean Architecture while reducing conceptual fragmentation.

In classic Clean Architecture, concepts such as Entity, Model, Use Case, and Interactor are often separated.
In practice, this separation can lead to duplicated responsibilities, higher cognitive load, and extra maintenance cost.

This approach favors:

  • A small number of well-defined concepts
  • Clear ownership of behavior
  • Predictable interaction between layers

The intention is consistency and maintainability, not theoretical purity.


About Entities in This Architecture

In traditional Clean Architecture:

  • Entities represent enterprise business rules
  • Models represent persistence concerns

In this architecture, these concepts are merged into a single Entity.

An Entity:

  • Represents a domain concept
  • Holds state and behavior
  • May include persistence mapping
  • Is not treated only as a storage structure

This removes ambiguity and encourages a behavior-first mindset, rather than a database-first one.

When external references define entities differently, the definition in this document represents the standard used by the team.


Core Concepts

Entity

Represents a domain object with state and behavior.

  • Encapsulates business rules related to itself
  • Controls how its state changes
  • Independent of application flow

→ Details and examples: entities.md


Use Case

Represents an application action or intent.

  • Coordinates entities
  • Defines application flow
  • Receives input and produces an outcome

→ Details and examples: use-cases.md


Service

Represents a pluggable external or third-party capability.

Services are used whenever something is integrated into the system, such as:

  • External APIs
  • Messaging systems
  • Payment providers
  • File storage
  • Any replaceable external tool

Characteristics:

  • Always defined by an interface
  • Implementation can be swapped without affecting core logic
  • Executes a capability but does not orchestrate application flow

→ Details and examples: services.md


Repository

Represents access to persisted entities.

  • Loads and saves entities
  • Hides persistence details
  • Does not contain business rules

→ Details and examples: repositories.md


Interactions

A common interaction flow looks like this:

Controller → Use Case → Entity
↓
Service / Repository

This flow keeps responsibilities explicit and dependencies predictable.

→ Interaction patterns and variations: interactions.md


Testing

Testing in this architecture focuses primarily on unit tests.

Unit tests provide fast feedback, protect behavior, and help keep responsibilities clear across entities and use cases.

The goal of testing is confidence, not coverage metrics or test quantity.


Unit Tests

Unit tests are the main and preferred form of testing.

They focus on:

  • Entity behavior
  • Use case execution
  • Clear inputs and outputs
  • State transitions and invariants

Well-written unit tests should:

  • Run fast
  • Avoid infrastructure
  • Be easy to read
  • Be easy to maintain

What We Unit Test

Entities

  • Test behavior through public methods
  • Validate state changes
  • Ensure invariants are enforced

Use Cases

  • Test execution flow
  • Validate interactions with entities
  • Use mocks or fakes for repositories and services

What We Avoid in Unit Tests

Unit tests should not:

  • Boot the framework
  • Use a real database
  • Use the service container
  • Depend on external systems

These concerns belong to other types of tests and are intentionally out of scope here.


About TDD

Test-Driven Development (TDD) is encouraged but not required.

When used, TDD can help:

  • Clarify intent before implementation
  • Drive better APIs for entities and use cases
  • Keep code focused on behavior

TDD is a technique, not a rule.

The important part is that behavior is testable and tested, regardless of the order in which code and tests are written.


Testing as Design Feedback

Tests are not only a safety net, but also a design tool.

If a piece of code is impossible to unit test, it is usually a sign of bad design.

Common indicators include:

  • Too many responsibilities
  • Hidden dependencies
  • Tight coupling to infrastructure
  • Unclear boundaries

Improving the design usually improves testability as well.


Summary

  • Unit tests are the primary testing strategy
  • Entities and use cases are the main focus
  • Infrastructure is excluded from unit tests
  • TDD is optional, clarity is not

Testing exists to support maintainability and confidence — not to slow development down.


Examples

Examples illustrate common situations and design decisions.

They are intentionally small and focused, serving as reference rather than templates.

→ Browse examples: examples/README.md


Frameworks

Core architectural concepts remain the same across frameworks.
This section documents how those concepts map to specific frameworks.


Framework: Symfony

Symfony-specific guidance focused on applying entities, use cases, services, and repositories within the framework.

Topics include:

  • Controllers as entry points
  • Dependency injection and the service container
  • Doctrine usage in relation to entities
  • Console commands and background processes

→ Symfony architecture guide: frameworks/symfony/README.md


AI Assistance (Claude)

This repository includes an AI context file used to keep AI-assisted development aligned with our architectural patterns.

The file is located at:

claude.md

How to use it

When using Claude (or any LLM) to generate code or discuss architecture:

  1. Open claude.md
  2. Copy the entire content
  3. Paste it into Claude as context / system instructions
  4. Then ask your question or request code

This ensures AI-generated suggestions follow the same rules and boundaries used by the team (Entity, Use Case, Service, Repository).

If AI suggestions conflict with the architecture, the rules in claude.md take precedence.


About

This documentation describes the core architectural concepts used across backend systems and how they interact.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Architecture

This document describes how backend code is structured and how the main parts interact.

It defines a single, shared approach used by the team to keep systems easy to understand, easy to change, and consistent over time.

The approach is inspired by Clean Architecture and DDD, but intentionally simplified to avoid unnecessary layers and overhead.
The goal is to provide one clear way of thinking and coding as a team.

The initial design and consolidation of these ideas were proposed by Vinicius Rangel.
If questions arise about decisions or trade-offs, they can be discussed directly.


Table of Contents

  1. Architectural Approach
  2. Core Concepts
  3. Interactions
  4. Testing
  5. Examples
  6. Frameworks
  7. IA

Architectural Approach

This architecture borrows the most valuable ideas from Clean Architecture while reducing conceptual fragmentation.

In classic Clean Architecture, concepts such as Entity, Model, Use Case, and Interactor are often separated.
In practice, this separation can lead to duplicated responsibilities, higher cognitive load, and extra maintenance cost.

This approach favors:

  • A small number of well-defined concepts
  • Clear ownership of behavior
  • Predictable interaction between layers

The intention is consistency and maintainability, not theoretical purity.


About Entities in This Architecture

In traditional Clean Architecture:

  • Entities represent enterprise business rules
  • Models represent persistence concerns

In this architecture, these concepts are merged into a single Entity.

An Entity:

  • Represents a domain concept
  • Holds state and behavior
  • May include persistence mapping
  • Is not treated only as a storage structure

This removes ambiguity and encourages a behavior-first mindset, rather than a database-first one.

When external references define entities differently, the definition in this document represents the standard used by the team.


Core Concepts

Entity

Represents a domain object with state and behavior.

  • Encapsulates business rules related to itself
  • Controls how its state changes
  • Independent of application flow

→ Details and examples: entities.md


Use Case

Represents an application action or intent.

  • Coordinates entities
  • Defines application flow
  • Receives input and produces an outcome

→ Details and examples: use-cases.md


Service

Represents a pluggable external or third-party capability.

Services are used whenever something is integrated into the system, such as:

  • External APIs
  • Messaging systems
  • Payment providers
  • File storage
  • Any replaceable external tool

Characteristics:

  • Always defined by an interface
  • Implementation can be swapped without affecting core logic
  • Executes a capability but does not orchestrate application flow

→ Details and examples: services.md


Repository

Represents access to persisted entities.

  • Loads and saves entities
  • Hides persistence details
  • Does not contain business rules

→ Details and examples: repositories.md


Interactions

A common interaction flow looks like this:

Controller → Use Case → Entity
↓
Service / Repository

This flow keeps responsibilities explicit and dependencies predictable.

→ Interaction patterns and variations: interactions.md


Testing

Testing in this architecture focuses primarily on unit tests.

Unit tests provide fast feedback, protect behavior, and help keep responsibilities clear across entities and use cases.

The goal of testing is confidence, not coverage metrics or test quantity.


Unit Tests

Unit tests are the main and preferred form of testing.

They focus on:

  • Entity behavior
  • Use case execution
  • Clear inputs and outputs
  • State transitions and invariants

Well-written unit tests should:

  • Run fast
  • Avoid infrastructure
  • Be easy to read
  • Be easy to maintain

What We Unit Test

Entities

  • Test behavior through public methods
  • Validate state changes
  • Ensure invariants are enforced

Use Cases

  • Test execution flow
  • Validate interactions with entities
  • Use mocks or fakes for repositories and services

What We Avoid in Unit Tests

Unit tests should not:

  • Boot the framework
  • Use a real database
  • Use the service container
  • Depend on external systems

These concerns belong to other types of tests and are intentionally out of scope here.


About TDD

Test-Driven Development (TDD) is encouraged but not required.

When used, TDD can help:

  • Clarify intent before implementation
  • Drive better APIs for entities and use cases
  • Keep code focused on behavior

TDD is a technique, not a rule.

The important part is that behavior is testable and tested, regardless of the order in which code and tests are written.


Testing as Design Feedback

Tests are not only a safety net, but also a design tool.

If a piece of code is impossible to unit test, it is usually a sign of bad design.

Common indicators include:

  • Too many responsibilities
  • Hidden dependencies
  • Tight coupling to infrastructure
  • Unclear boundaries

Improving the design usually improves testability as well.


Summary

  • Unit tests are the primary testing strategy
  • Entities and use cases are the main focus
  • Infrastructure is excluded from unit tests
  • TDD is optional, clarity is not

Testing exists to support maintainability and confidence — not to slow development down.


Examples

Examples illustrate common situations and design decisions.

They are intentionally small and focused, serving as reference rather than templates.

→ Browse examples: examples/README.md


Frameworks

Core architectural concepts remain the same across frameworks.
This section documents how those concepts map to specific frameworks.


Framework: Symfony

Symfony-specific guidance focused on applying entities, use cases, services, and repositories within the framework.

Topics include:

  • Controllers as entry points
  • Dependency injection and the service container
  • Doctrine usage in relation to entities
  • Console commands and background processes

→ Symfony architecture guide: frameworks/symfony/README.md


AI Assistance (Claude)

This repository includes an AI context file used to keep AI-assisted development aligned with our architectural patterns.

The file is located at:

claude.md

How to use it

When using Claude (or any LLM) to generate code or discuss architecture:

  1. Open claude.md
  2. Copy the entire content
  3. Paste it into Claude as context / system instructions
  4. Then ask your question or request code

This ensures AI-generated suggestions follow the same rules and boundaries used by the team (Entity, Use Case, Service, Repository).

If AI suggestions conflict with the architecture, the rules in claude.md take precedence.


About

This documentation describes the core architectural concepts used across backend systems and how they interact.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

Architecture

This document describes how backend code is structured and how the main parts interact.

It defines a single, shared approach used by the team to keep systems easy to understand, easy to change, and consistent over time.

The approach is inspired by Clean Architecture and DDD, but intentionally simplified to avoid unnecessary layers and overhead.
The goal is to provide one clear way of thinking and coding as a team.

The initial design and consolidation of these ideas were proposed by Vinicius Rangel.
If questions arise about decisions or trade-offs, they can be discussed directly.


Table of Contents

  1. Architectural Approach
  2. Core Concepts
  3. Interactions
  4. Testing
  5. Examples
  6. Frameworks
  7. IA

Architectural Approach

This architecture borrows the most valuable ideas from Clean Architecture while reducing conceptual fragmentation.

In classic Clean Architecture, concepts such as Entity, Model, Use Case, and Interactor are often separated.
In practice, this separation can lead to duplicated responsibilities, higher cognitive load, and extra maintenance cost.

This approach favors:

  • A small number of well-defined concepts
  • Clear ownership of behavior
  • Predictable interaction between layers

The intention is consistency and maintainability, not theoretical purity.


About Entities in This Architecture

In traditional Clean Architecture:

  • Entities represent enterprise business rules
  • Models represent persistence concerns

In this architecture, these concepts are merged into a single Entity.

An Entity:

  • Represents a domain concept
  • Holds state and behavior
  • May include persistence mapping
  • Is not treated only as a storage structure

This removes ambiguity and encourages a behavior-first mindset, rather than a database-first one.

When external references define entities differently, the definition in this document represents the standard used by the team.


Core Concepts

Entity

Represents a domain object with state and behavior.

  • Encapsulates business rules related to itself
  • Controls how its state changes
  • Independent of application flow

→ Details and examples: entities.md


Use Case

Represents an application action or intent.

  • Coordinates entities
  • Defines application flow
  • Receives input and produces an outcome

→ Details and examples: use-cases.md


Service

Represents a pluggable external or third-party capability.

Services are used whenever something is integrated into the system, such as:

  • External APIs
  • Messaging systems
  • Payment providers
  • File storage
  • Any replaceable external tool

Characteristics:

  • Always defined by an interface
  • Implementation can be swapped without affecting core logic
  • Executes a capability but does not orchestrate application flow

→ Details and examples: services.md


Repository

Represents access to persisted entities.

  • Loads and saves entities
  • Hides persistence details
  • Does not contain business rules

→ Details and examples: repositories.md


Interactions

A common interaction flow looks like this:

Controller → Use Case → Entity
↓
Service / Repository

This flow keeps responsibilities explicit and dependencies predictable.

→ Interaction patterns and variations: interactions.md


Testing

Testing in this architecture focuses primarily on unit tests.

Unit tests provide fast feedback, protect behavior, and help keep responsibilities clear across entities and use cases.

The goal of testing is confidence, not coverage metrics or test quantity.


Unit Tests

Unit tests are the main and preferred form of testing.

They focus on:

  • Entity behavior
  • Use case execution
  • Clear inputs and outputs
  • State transitions and invariants

Well-written unit tests should:

  • Run fast
  • Avoid infrastructure
  • Be easy to read
  • Be easy to maintain

What We Unit Test

Entities

  • Test behavior through public methods
  • Validate state changes
  • Ensure invariants are enforced

Use Cases

  • Test execution flow
  • Validate interactions with entities
  • Use mocks or fakes for repositories and services

What We Avoid in Unit Tests

Unit tests should not:

  • Boot the framework
  • Use a real database
  • Use the service container
  • Depend on external systems

These concerns belong to other types of tests and are intentionally out of scope here.


About TDD

Test-Driven Development (TDD) is encouraged but not required.

When used, TDD can help:

  • Clarify intent before implementation
  • Drive better APIs for entities and use cases
  • Keep code focused on behavior

TDD is a technique, not a rule.

The important part is that behavior is testable and tested, regardless of the order in which code and tests are written.


Testing as Design Feedback

Tests are not only a safety net, but also a design tool.

If a piece of code is impossible to unit test, it is usually a sign of bad design.

Common indicators include:

  • Too many responsibilities
  • Hidden dependencies
  • Tight coupling to infrastructure
  • Unclear boundaries

Improving the design usually improves testability as well.


Summary

  • Unit tests are the primary testing strategy
  • Entities and use cases are the main focus
  • Infrastructure is excluded from unit tests
  • TDD is optional, clarity is not

Testing exists to support maintainability and confidence — not to slow development down.


Examples

Examples illustrate common situations and design decisions.

They are intentionally small and focused, serving as reference rather than templates.

→ Browse examples: examples/README.md


Frameworks

Core architectural concepts remain the same across frameworks.
This section documents how those concepts map to specific frameworks.


Framework: Symfony

Symfony-specific guidance focused on applying entities, use cases, services, and repositories within the framework.

Topics include:

  • Controllers as entry points
  • Dependency injection and the service container
  • Doctrine usage in relation to entities
  • Console commands and background processes

→ Symfony architecture guide: frameworks/symfony/README.md


AI Assistance (Claude)

This repository includes an AI context file used to keep AI-assisted development aligned with our architectural patterns.

The file is located at:

claude.md

How to use it

When using Claude (or any LLM) to generate code or discuss architecture:

  1. Open claude.md
  2. Copy the entire content
  3. Paste it into Claude as context / system instructions
  4. Then ask your question or request code

This ensures AI-generated suggestions follow the same rules and boundaries used by the team (Entity, Use Case, Service, Repository).

If AI suggestions conflict with the architecture, the rules in claude.md take precedence.


About

This documentation describes the core architectural concepts used across backend systems and how they interact.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

Architecture

This document describes how backend code is structured and how the main parts interact.

It defines a single, shared approach used by the team to keep systems easy to understand, easy to change, and consistent over time.

The approach is inspired by Clean Architecture and DDD, but intentionally simplified to avoid unnecessary layers and overhead.
The goal is to provide one clear way of thinking and coding as a team.

The initial design and consolidation of these ideas were proposed by Vinicius Rangel.
If questions arise about decisions or trade-offs, they can be discussed directly.


Table of Contents

  1. Architectural Approach
  2. Core Concepts
  3. Interactions
  4. Testing
  5. Examples
  6. Frameworks
  7. IA

Architectural Approach

This architecture borrows the most valuable ideas from Clean Architecture while reducing conceptual fragmentation.

In classic Clean Architecture, concepts such as Entity, Model, Use Case, and Interactor are often separated.
In practice, this separation can lead to duplicated responsibilities, higher cognitive load, and extra maintenance cost.

This approach favors:

  • A small number of well-defined concepts
  • Clear ownership of behavior
  • Predictable interaction between layers

The intention is consistency and maintainability, not theoretical purity.


About Entities in This Architecture

In traditional Clean Architecture:

  • Entities represent enterprise business rules
  • Models represent persistence concerns

In this architecture, these concepts are merged into a single Entity.

An Entity:

  • Represents a domain concept
  • Holds state and behavior
  • May include persistence mapping
  • Is not treated only as a storage structure

This removes ambiguity and encourages a behavior-first mindset, rather than a database-first one.

When external references define entities differently, the definition in this document represents the standard used by the team.


Core Concepts

Entity

Represents a domain object with state and behavior.

  • Encapsulates business rules related to itself
  • Controls how its state changes
  • Independent of application flow

→ Details and examples: entities.md


Use Case

Represents an application action or intent.

  • Coordinates entities
  • Defines application flow
  • Receives input and produces an outcome

→ Details and examples: use-cases.md


Service

Represents a pluggable external or third-party capability.

Services are used whenever something is integrated into the system, such as:

  • External APIs
  • Messaging systems
  • Payment providers
  • File storage
  • Any replaceable external tool

Characteristics:

  • Always defined by an interface
  • Implementation can be swapped without affecting core logic
  • Executes a capability but does not orchestrate application flow

→ Details and examples: services.md


Repository

Represents access to persisted entities.

  • Loads and saves entities
  • Hides persistence details
  • Does not contain business rules

→ Details and examples: repositories.md


Interactions

A common interaction flow looks like this:

Controller → Use Case → Entity
↓
Service / Repository

This flow keeps responsibilities explicit and dependencies predictable.

→ Interaction patterns and variations: interactions.md


Testing

Testing in this architecture focuses primarily on unit tests.

Unit tests provide fast feedback, protect behavior, and help keep responsibilities clear across entities and use cases.

The goal of testing is confidence, not coverage metrics or test quantity.


Unit Tests

Unit tests are the main and preferred form of testing.

They focus on:

  • Entity behavior
  • Use case execution
  • Clear inputs and outputs
  • State transitions and invariants

Well-written unit tests should:

  • Run fast
  • Avoid infrastructure
  • Be easy to read
  • Be easy to maintain

What We Unit Test

Entities

  • Test behavior through public methods
  • Validate state changes
  • Ensure invariants are enforced

Use Cases

  • Test execution flow
  • Validate interactions with entities
  • Use mocks or fakes for repositories and services

What We Avoid in Unit Tests

Unit tests should not:

  • Boot the framework
  • Use a real database
  • Use the service container
  • Depend on external systems

These concerns belong to other types of tests and are intentionally out of scope here.


About TDD

Test-Driven Development (TDD) is encouraged but not required.

When used, TDD can help:

  • Clarify intent before implementation
  • Drive better APIs for entities and use cases
  • Keep code focused on behavior

TDD is a technique, not a rule.

The important part is that behavior is testable and tested, regardless of the order in which code and tests are written.


Testing as Design Feedback

Tests are not only a safety net, but also a design tool.

If a piece of code is impossible to unit test, it is usually a sign of bad design.

Common indicators include:

  • Too many responsibilities
  • Hidden dependencies
  • Tight coupling to infrastructure
  • Unclear boundaries

Improving the design usually improves testability as well.


Summary

  • Unit tests are the primary testing strategy
  • Entities and use cases are the main focus
  • Infrastructure is excluded from unit tests
  • TDD is optional, clarity is not

Testing exists to support maintainability and confidence — not to slow development down.


Examples

Examples illustrate common situations and design decisions.

They are intentionally small and focused, serving as reference rather than templates.

→ Browse examples: examples/README.md


Frameworks

Core architectural concepts remain the same across frameworks.
This section documents how those concepts map to specific frameworks.


Framework: Symfony

Symfony-specific guidance focused on applying entities, use cases, services, and repositories within the framework.

Topics include:

  • Controllers as entry points
  • Dependency injection and the service container
  • Doctrine usage in relation to entities
  • Console commands and background processes

→ Symfony architecture guide: frameworks/symfony/README.md


AI Assistance (Claude)

This repository includes an AI context file used to keep AI-assisted development aligned with our architectural patterns.

The file is located at:

claude.md

How to use it

When using Claude (or any LLM) to generate code or discuss architecture:

  1. Open claude.md
  2. Copy the entire content
  3. Paste it into Claude as context / system instructions
  4. Then ask your question or request code

This ensures AI-generated suggestions follow the same rules and boundaries used by the team (Entity, Use Case, Service, Repository).

If AI suggestions conflict with the architecture, the rules in claude.md take precedence.


About

This documentation describes the core architectural concepts used across backend systems and how they interact.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors