Use when adding new error messages to React, or seeing "unknown error code" warnings.
npx skills add YuniorGlez/gemini-elite-core --skill "architect-pro"
Install specific skill from multi-skill repository
# Description
Advanced Software Architecture Masterclass. Implements Clean Architecture, Hexagonal (Ports & Adapters), and DDD for 2026 ecosystems (Next.js 16.2, React 19.3, Node.js 24). Optimized for AI-driven development.
# SKILL.md
name: architect-pro
description: Advanced Software Architecture Masterclass. Implements Clean Architecture, Hexagonal (Ports & Adapters), and DDD for 2026 ecosystems (Next.js 16.2, React 19.3, Node.js 24). Optimized for AI-driven development.
Architect Pro: Advanced Software Architecture (2026 Edition)
Master the art of building maintainable, scalable, and testable systems using proven architectural patterns. This skill is optimized for the Next.js 16.2 / React 19.3 / Node.js 24 ecosystem, focusing on decoupling business logic from infrastructure and enabling Autonomous AI Agents to work effectively within your codebase.
π Prerequisites & Skill Level
- Level: Senior / Lead Engineer / Software Architect
- Prerequisites:
- Deep understanding of TypeScript 5.5+ (Generics, Discriminated Unions, Template Literal Types).
- Familiarity with Next.js App Router and Server Components.
- Basic knowledge of SQL (PostgreSQL) and NoSQL (Redis/MongoDB) databases.
- Experience with automated testing (Jest, Vitest, Playwright).
- Interest in Domain-Driven Design (DDD).
π Table of Contents
- Core Philosophy
- Why Clean Architecture in 2026?
- Architecture for AI Agents
- Quick Start: The 2026 Stack
- Modern Data Flow: React 19 + Next.js 16
- Standard Pattern: Clean Architecture + Server Actions
- Tactical DDD: Entities, Value Objects, and Aggregates
- Domain Services vs Application Services
- Advanced Pattern: Event-Driven DDD
- Event Storming & Domain Modeling
- Architecture Decision Records (ADR)
- Context Mapping & Strategic DDD
- Testing Strategy for Architects
- Architectural Enforcement & Guardrails
- Performance & Scalability at the Architectural Level
- Glossary of Architectural Terms
- The Do Not List (Anti-Patterns)
- Deep-Dive References
- Repository Analysis with Repomix
ποΈ Core Philosophy
In 2026, software is increasingly built and refactored by AI Coding Agents. For an agent to be effective, the codebase must have predictable boundaries and explicit contracts.
- Decoupling: Business logic (Domain) must not depend on the database, UI, or frameworks.
- Testability: You should be able to test your core logic without spinning up a database or mocking complex framework internals.
- Independence: The system should be agnostic of its delivery mechanisms (Web, CLI, Mobile, AI Agents).
- Predictability: Files and folders should follow a strict convention so that both humans and AI can locate logic instantly.
π§ Why Clean Architecture in 2026?
The "Move Fast and Break Things" era has evolved into the "Move Fast with AI and Maintain Sanity" era. Without a solid architecture:
1. AI Agents Hallucinate: When business logic is mixed with Prisma queries and React hooks, AI often loses context and introduces subtle bugs.
2. Framework Churn: Next.js and React versions move fast. A clean domain layer protects you from the next breaking change in the app router or server actions.
3. Complexity Debt: What starts as a simple "CRUD" app often grows into a complex domain. Clean Architecture allows for "Gradual Complexity" where you can add layers only when needed.
π€ Architecture for AI Agents
In 2026, we design for two audiences: Humans and Agents.
- Deterministic File Paths: Using a strict Clean Architecture folder structure helps AI find the "Source of Truth" (Domain) instantly.
- Strong Typing (TS 5.5+): Explicit return types in Use Cases act as "API Documentation" for AI agents.
- Small Context Windows: Decoupled layers allow AI to work on a single file (like a Use Case) without needing to understand the entire database schema.
- Repomix Context Packing: We use tools to pack high-density context for AI agents, and a clean architecture makes this packing 10x more efficient.
β‘ Quick Start: The 2026 Stack
The most common production stack in 2026 uses Next.js 16.2 with Server Functions, TypeScript 5.x, and Bun/pnpm monorepos.
Recommended Folder Structure
src/
βββ domain/ # Core Logic (The "Truth")
β βββ entities/ # Identifiable objects with identity and lifecycle
β βββ value-objects/# Data wrappers with validation (Email, Money)
β βββ services/ # Pure logic involving multiple entities
β βββ events/ # Domain Events (OrderPlaced, UserDeactivated)
β βββ exceptions/ # Custom domain exceptions
βββ application/ # Orchestration (The "User's Intent")
β βββ use-cases/ # Specific business actions (Commands)
β βββ ports/ # Interfaces (contracts for Infrastructure)
β βββ dtos/ # Data Transfer Objects
β βββ queries/ # Read-only operations (if using CQRS)
βββ infrastructure/ # Tools (The "Implementation")
β βββ adapters/ # Implementations of Ports (Prisma, Stripe, AWS)
β βββ persistence/ # DB Schemas, Migrations, Seeders
β βββ external/ # Third-party API clients
βββ presentation/ # UI (The "View")
β βββ components/ # React 19 Server/Client components
β βββ actions/ # Next.js Server Actions (Primary Adapters)
β βββ pages/ # Route Handlers and Page definitions
βββ shared/ # Cross-cutting concerns (Constants, Utils)
π Modern Data Flow: React 19 + Next.js 16
The interaction model has changed. We no longer just "fetch from API". We "Invoke a Service".
1. View (React 19)
Uses the new useActionState and useOptimistic for a seamless UX.
// presentation/components/ProjectForm.tsx
'use client'
import { useActionState } from 'react';
import { createProjectAction } from '../actions/project-actions';
export function ProjectForm() {
const [state, formAction, isPending] = useActionState(createProjectAction, null);
return (
<form action={formAction}>
<div className="flex flex-col gap-4">
<label htmlFor="projectName">Project Name</label>
<input
id="projectName"
name="projectName"
className="border p-2 rounded"
required
/>
<button
className="bg-blue-600 text-white p-2 rounded"
disabled={isPending}
>
{isPending ? 'Creating...' : 'Create Project'}
</button>
{state?.error && <p className="text-red-500">{state.error}</p>}
</div>
</form>
);
}
2. Action (Next.js 16.2)
Acts as the Primary Adapter. It handles the transition from HTTP (FormData) to Application logic.
// presentation/actions/project-actions.ts
'use server'
import { CreateProjectUseCase } from '@/application/use-cases/CreateProject';
import { PrismaProjectRepository } from '@/infrastructure/adapters/PrismaProjectRepository';
export async function createProjectAction(prevState: any, formData: FormData) {
const name = formData.get('projectName') as string;
// Dependency Injection: In 2026, we prefer explicit composition over complex DI containers
const repo = new PrismaProjectRepository();
const useCase = new CreateProjectUseCase(repo);
try {
const project = await useCase.execute({ name });
return { success: true, data: project };
} catch (e) {
// Audit log or Error tracking integration
console.error("[Action Error]", e);
return { success: false, error: e.message };
}
}
π οΈ Standard Pattern: Clean Architecture + Server Actions
1. The Domain Entity
Entities represent business concepts with identity.
// src/domain/entities/User.ts
import { Email } from '../value-objects/Email';
export class User {
constructor(
public readonly id: string,
public readonly email: Email,
private _isActive: boolean = true
) {}
public deactivate() {
this._isActive = false;
}
get isActive() { return this._isActive; }
}
2. The Use Case (Application Layer)
Use Cases orchestrate the domain objects to perform a specific task.
// src/application/use-cases/DeactivateUser.ts
import { IUserRepository } from '../ports/IUserRepository';
export class DeactivateUserUseCase {
constructor(private userRepo: IUserRepository) {}
async execute(userId: string): Promise<void> {
// 1. Fetch from repository (Port)
const user = await this.userRepo.findById(userId);
if (!user) throw new Error("User not found");
// 2. Perform domain logic (Entity)
user.deactivate();
// 3. Persist changes (Port)
await this.userRepo.save(user);
}
}
3. The Repository Implementation (Infrastructure)
The "Adapter" that talks to the database.
// src/infrastructure/adapters/PrismaUserRepository.ts
import { IUserRepository } from '@/application/ports/IUserRepository';
import { User } from '@/domain/entities/User';
import { Email } from '@/domain/value-objects/Email';
import { prisma } from '../prisma';
export class PrismaUserRepository implements IUserRepository {
async findById(id: string): Promise<User | null> {
const data = await prisma.user.findUnique({ where: { id } });
if (!data) return null;
return new User(
data.id,
Email.create(data.email),
data.isActive
);
}
async save(user: User): Promise<void> {
await prisma.user.upsert({
where: { id: user.id },
update: { isActive: user.isActive },
create: {
id: user.id,
email: user.email.value,
isActive: user.isActive
}
});
}
}
π§© Tactical DDD: Entities, Value Objects, and Aggregates
Value Objects (The Power of Types)
Don't use string for everything. Use Value Objects for validation and business logic.
// domain/value-objects/Money.ts
export class Money {
private constructor(public readonly amount: number, public readonly currency: string) {}
static create(amount: number, currency: string = 'USD'): Money {
if (amount < 0) throw new Error("Amount cannot be negative");
return new Money(amount, currency);
}
add(other: Money): Money {
if (this.currency !== other.currency) throw new Error("Currency mismatch");
return new Money(this.amount + other.amount, this.currency);
}
}
Aggregates (The Consistency Boundary)
An Aggregate ensures that business rules are always met across multiple related objects.
// domain/entities/Order.ts
export class Order {
private items: OrderItem[] = [];
addItem(product: Product, quantity: number) {
const totalItems = this.items.reduce((sum, item) => sum + item.quantity, 0);
if (totalItems + quantity > 50) {
throw new Error("An order cannot have more than 50 items");
}
this.items.push(new OrderItem(product.id, quantity));
}
}
βοΈ Domain Services vs Application Services
One of the most common points of confusion in DDD.
- Domain Service: Contains business logic that belongs to the domain but doesn't fit in a single entity (e.g.,
TransferServicebetween two bank accounts). It works with entities and value objects. - Application Service (Use Case): Contains NO business logic. It only orchestrates. It calls repositories, triggers domain services, and sends emails.
π Advanced Pattern: Event-Driven DDD
Capture intent and decouple side-effects.
Domain Service Example
// domain/services/TransferService.ts
export class TransferService {
async execute(from: Account, to: Account, amount: Money) {
from.withdraw(amount);
to.deposit(amount);
// Domain Events are captured here
return new FundsTransferredEvent(from.id, to.id, amount);
}
}
πͺοΈ Event Storming & Domain Modeling
In 2026, we don't start with "Tables". We start with "Events".
1. Domain Events: What happens in the business? (e.g., OrderPlaced, InventoryReduced).
2. Commands: What triggers these events? (e.g., PlaceOrder).
3. Aggregates: What objects are involved in making sure the rules are followed?
4. Read Models: How do we want to display this information to the user?
π Architecture Decision Records (ADR)
In 2026, we record why we made a choice, not just what we chose.
# ADR 005: Use Clean Architecture for AI Core
## Status
Accepted
## Context
We need a way for AI agents to refactor code safely without breaking business rules. The previous "Spaghetti Monolith" resulted in AI hallucinating database queries in React components.
## Decision
We will use Clean Architecture with strict separation between Domain and Infrastructure.
## Consequences
- Pros: Predictable file structure, high testability, zero framework leakage in domain.
- Cons: More boilerplate for simple CRUD operations, higher learning curve for junior devs.
πΊοΈ Context Mapping & Strategic DDD
How different parts of the system talk to each other.
- Customer/Supplier: One team depends on another.
- Shared Kernel: Two teams share a common model (rarely recommended).
- Anticorruption Layer (ACL): A layer that translates between a legacy system and your clean new system.
- Separate Ways: No relationship between contexts.
π§ͺ Testing Strategy for Architects
In a Clean Architecture, you have different "Testing Grooves":
- Domain Unit Tests: Test entities and value objects. ZERO mocks needed. 100% code coverage expected here.
- Use Case Tests: Test orchestration. Use In-Memory Adapters (Mocks/Fakes) for the database.
- Integration Tests: Test the real adapters (e.g., Prisma repository against a real Test Container).
- E2E Tests: Test the full Next.js flow using Playwright.
Example: Use Case Test (No DB)
// tests/use-cases/DeactivateUser.test.ts
import { DeactivateUserUseCase } from '@/application/use-cases/DeactivateUser';
import { InMemoryUserRepository } from '../mocks/InMemoryUserRepository';
test('should deactivate user', async () => {
const repo = new InMemoryUserRepository();
await repo.save({ id: '1', email: '[email protected]', isActive: true });
const useCase = new DeactivateUserUseCase(repo);
await useCase.execute('1');
const user = await repo.findById('1');
expect(user.isActive).toBe(false);
});
π‘οΈ Architectural Enforcement & Guardrails
Use tools to ensure the "Dependency Rule" is never broken.
dependency-cruiser config (2026 best practice)
{
"forbidden": [
{
"name": "domain-not-import-infra",
"from": { "path": "src/domain" },
"to": { "path": "src/infrastructure" }
},
{
"name": "usecase-not-import-infra",
"from": { "path": "src/application" },
"to": { "path": "src/infrastructure" }
},
{
"name": "presentation-not-import-infra",
"from": { "path": "src/presentation" },
"to": { "path": "src/infrastructure" }
}
]
}
π Performance & Scalability at the Architectural Level
- Read-Write Segregation (CQRS): Use a fast NoSQL database for reads and a robust SQL database for writes.
- Caching as a First-Class Citizen: Don't put cache logic in your Use Case. Use a Caching Adapter or the Next.js
use cachedirective in the presentation layer. - Job Queues: Offload heavy work (Email, AI Processing) to background jobs via Domain Events.
π Glossary of Architectural Terms
- Bounded Context: A specific boundary (usually a module or service) where a domain model is consistent.
- Port: An interface defined by the application layer that infrastructure must implement.
- Adapter: An implementation of a port (e.g., a SQL database implementation of an
IUserRepository). - Inversion of Control (IoC): The principle where the domain defines its needs (Ports), and the high-level layers provide the implementations (Adapters).
- Aggregate Root: The main entity in an aggregate that controls all access and enforces business rules.
- Ubiquitous Language: A common language used by all team members to describe the domain.
π« The Do Not List (Anti-Patterns)
1. Framework Leakage
BAD: Using @prisma/client types as return types in your Domain or Application layers.
GOOD: Map database rows to Domain Entities in the Infrastructure layer.
2. Anemic Domain Model
BAD: Putting all your logic in UserService and having User as just a type.
GOOD: Move business rules (e.g., user.canJoinProject()) into the User class.
3. The "Shared" Dumpster
BAD: Putting everything in shared/ because you are too lazy to decide where it belongs.
GOOD: Keep shared/ minimal. If it's business-related, it's domain/. If it's tool-related, it's infrastructure/.
4. Premature Microservices
BAD: Splitting into 10 repos before you understand the domain boundaries.
GOOD: Build a Modular Monolith using Clean Architecture first. Boundaries are easy to cut later if they are clean.
5. Lazy Naming
BAD: data, info, manager, process.
GOOD: PaymentRecord, UserAuthenticationDetails, OrderOrchestrator.
π Deep-Dive References
Explore our specialized documentation for deeper technical insights:
- Clean Architecture Guide
- Hexagonal Architecture (Ports & Adapters)
- DDD Patterns & Tactical Design
- Performance & Scalability 2026
- Migration & Refactoring Strategies
- Repository Analysis Guide
π Repository Analysis with Repomix
Before refactoring, always analyze the existing codebase structure.
# Optimized command for architecture discovery
npx repomix@latest --include "src/**/*.ts" --compress --output /tmp/arch-discovery.xml
Using Repomix allows you to "pack" your architecture into a single file that can be fed into an AI for a full audit.
π Best Practices Checklist
- [ ] Is my Domain Layer free of external dependencies?
- [ ] Are my Use Cases doing only orchestration?
- [ ] Do I have interfaces (Ports) for all external services (DB, Auth, Mail, Stripe)?
- [ ] Am I using Value Objects for things like Email, Money, and Address?
- [ ] Is my code testable without a real database?
- [ ] Have I mapped my infrastructure errors to domain exceptions?
- [ ] Have I used ADRs to document major architectural decisions?
- [ ] Is my ubiquitous language reflected in the code?
Updated: January 22, 2026 - 15:18
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.