feat: add hexagonal architecture SKILL.#1034
Conversation
📝 WalkthroughWalkthroughA new Hexagonal Architecture skill documentation file is added, covering architectural principles, design patterns, implementation examples in TypeScript, cross-language guidance, anti-patterns, migration strategies, and testing practices. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR adds
Confidence Score: 5/5Safe to merge — this is a documentation-only addition with no executable code, no secrets, and no impact on existing functionality. All findings are P2 style/completeness suggestions (one minor wording consistency in the immutable-return example, one missing inbound adapter snippet). There are no P0 or P1 issues. The skill follows the established format, is placed in the correct directory, and the content is technically sound. No files require special attention; the single changed file is a markdown skill document with no executable logic. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
Client["Client (HTTP / CLI / Worker)"] --> InboundAdapter["Inbound Adapter\n(e.g. createOrderRoute.ts)"]
InboundAdapter -->|"maps protocol input →\nuse-case input"| UseCase["Use Case\n(CreateOrderUseCase)"]
UseCase -->|"calls"| OutboundPort1["Outbound Port\n(OrderRepositoryPort)"]
UseCase -->|"calls"| OutboundPort2["Outbound Port\n(PaymentGatewayPort)"]
UseCase -->|"orchestrates"| Domain["Domain Model\n(Order, OrderPolicy)"]
OutboundAdapter1["Outbound Adapter\n(PostgresOrderRepository)"] -->|"implements"| OutboundPort1
OutboundAdapter2["Outbound Adapter\n(StripePaymentGateway)"] -->|"implements"| OutboundPort2
OutboundAdapter1 --> DB[("PostgreSQL")]
OutboundAdapter2 --> Stripe["Stripe API"]
CompositionRoot["Composition Root\n(ordersContainer.ts)"] -.->|"wires"| UseCase
CompositionRoot -.->|"instantiates"| OutboundAdapter1
CompositionRoot -.->|"instantiates"| OutboundAdapter2
Reviews (1): Last reviewed commit: "feat: add hexagonal architecture SKILL." | Re-trigger Greptile |
| return { | ||
| orderId: order.id, | ||
| authorizationId: auth.authorizationId, | ||
| }; | ||
| } | ||
| } |
There was a problem hiding this comment.
Use
authorizedOrder.id for consistency in return value
The execute method saves authorizedOrder (the post-markAuthorized instance) to the repository, but the returned DTO still references order.id. Since markAuthorized only changes the authorization state and not the ID, the values are identical at runtime — however, for a reference document that explicitly demonstrates immutable transformations, using authorizedOrder.id in the output would reinforce the principle and avoid any reader confusion about which object's data is being returned.
| return { | |
| orderId: order.id, | |
| authorizationId: auth.authorizationId, | |
| }; | |
| } | |
| } | |
| return { | |
| orderId: authorizedOrder.id, | |
| authorizationId: auth.authorizationId, | |
| }; |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| ordersContainer.ts | ||
| ``` | ||
|
|
||
| ## TypeScript Example |
There was a problem hiding this comment.
Missing inbound adapter TypeScript example
The ## TypeScript Example section covers port definitions, the use-case class, the outbound adapter, and the composition root — but omits an inbound adapter example. The module layout references createOrderRoute.ts, and the "Core Concepts" and "How It Works" sections describe inbound adapters as a first-class concern. Adding a short Express/Fastify route snippet (mapping req.body → CreateOrderInput → calling useCase.execute → mapping the result to an HTTP response) would make the section complete and directly illustrate the boundary that most readers will implement first.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
skills/hexagonal-architecture/SKILL.md (1)
119-202: LGTM! Comprehensive TypeScript example demonstrates key concepts.The TypeScript example effectively illustrates:
- Clean port interface definitions
- Use case orchestration with dependency injection
- Outbound adapter implementation
- Explicit composition root wiring
The comment at line 161 explaining immutability is helpful. The example correctly shows ports as abstractions with concrete implementations in adapters.
Consider showing the Order domain entity.
The example references
Order.create()(line 154),order.markAuthorized()(line 162), andOrder.rehydrate()(line 188), but theOrderdomain entity implementation is not shown. While the focus is on architecture boundaries, showing a brief domain entity example would make the skill more complete and help readers understand what "business rules and entities/value objects" (line 22) look like in practice.📝 Optional: Add Order domain entity example
Consider adding this example after line 122 or in a separate domain section:
// Domain entity - no framework dependencies export class Order { private constructor( public readonly id: string, public readonly amountCents: number, public readonly status: 'pending' | 'authorized', public readonly authorizationId?: string ) {} static create(props: { id: string; amountCents: number }): Order { if (props.amountCents <= 0) { throw new Error('Order amount must be positive'); } return new Order(props.id, props.amountCents, 'pending'); } markAuthorized(authorizationId: string): Order { return new Order(this.id, this.amountCents, 'authorized', authorizationId); } static rehydrate(row: any): Order { return new Order(row.id, row.amount_cents, row.status, row.authorization_id); } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/hexagonal-architecture/SKILL.md` around lines 119 - 202, Add a brief Order domain-entity example to the TypeScript sample so the referenced methods are defined: create a simple Order class that includes a static create(id, amountCents), an instance method markAuthorized(authorizationId) that returns a new Order, and a static rehydrate(row) to map DB rows to Order instances; insert this class near the top of the example (before CreateOrderUseCase) so calls to Order.create, order.markAuthorized, and Order.rehydrate resolve and readers can see the business-rule checks and immutability behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@skills/hexagonal-architecture/SKILL.md`:
- Around line 119-202: Add a brief Order domain-entity example to the TypeScript
sample so the referenced methods are defined: create a simple Order class that
includes a static create(id, amountCents), an instance method
markAuthorized(authorizationId) that returns a new Order, and a static
rehydrate(row) to map DB rows to Order instances; insert this class near the top
of the example (before CreateOrderUseCase) so calls to Order.create,
order.markAuthorized, and Order.rehydrate resolve and readers can see the
business-rule checks and immutability behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e0fa87cc-dc22-4281-a335-48d9a984fff4
📒 Files selected for processing (1)
skills/hexagonal-architecture/SKILL.md
There was a problem hiding this comment.
1 issue found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="skills/hexagonal-architecture/SKILL.md">
<violation number="1" location="skills/hexagonal-architecture/SKILL.md:156">
P2: The example authorizes payment before persisting the order, which can leave authorized payments without a saved order when persistence fails.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| async execute(input: CreateOrderInput): Promise<CreateOrderOutput> { | ||
| const order = Order.create({ id: input.orderId, amountCents: input.amountCents }); | ||
|
|
||
| const auth = await this.paymentGateway.authorize({ |
There was a problem hiding this comment.
P2: The example authorizes payment before persisting the order, which can leave authorized payments without a saved order when persistence fails.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At skills/hexagonal-architecture/SKILL.md, line 156:
<comment>The example authorizes payment before persisting the order, which can leave authorized payments without a saved order when persistence fails.</comment>
<file context>
@@ -0,0 +1,276 @@
+ async execute(input: CreateOrderInput): Promise<CreateOrderOutput> {
+ const order = Order.create({ id: input.orderId, amountCents: input.amountCents });
+
+ const auth = await this.paymentGateway.authorize({
+ orderId: order.id,
+ amountCents: order.amountCents,
</file context>
🚀 Add Hexagonal Architecture Skill
📌 Overview
This PR introduces a new skill: Hexagonal Architecture (Ports & Adapters).
The goal of this skill is to guide AI agents in designing and refactoring systems using a clean, maintainable, and testable architecture pattern that decouples business logic from infrastructure concerns.
🎯 Why this is useful
Hexagonal Architecture is widely used in modern backend systems to:
This aligns well with the repository’s focus on high-quality engineering patterns and reusable workflows.
🧠 What this skill provides
The skill helps agents:
⚙️ Capabilities
💡 Example use cases
📂 Structure
skills/hexagonal-architecture/🔍 Notes for reviewers
📈 Impact
This contribution enhances the repository by adding:
🙌 Future improvements (optional)