devhive 0.1.24__tar.gz → 0.1.25__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {devhive-0.1.24/devhive.egg-info → devhive-0.1.25}/PKG-INFO +4 -1
  2. {devhive-0.1.24 → devhive-0.1.25}/README.md +3 -0
  3. {devhive-0.1.24 → devhive-0.1.25/devhive.egg-info}/PKG-INFO +4 -1
  4. {devhive-0.1.24 → devhive-0.1.25}/devhive.egg-info/SOURCES.txt +1 -0
  5. {devhive-0.1.24 → devhive-0.1.25}/devhive_cli/main.py +29 -0
  6. devhive-0.1.25/devhive_cli/templates_backend.py +424 -0
  7. {devhive-0.1.24 → devhive-0.1.25}/setup.py +1 -1
  8. {devhive-0.1.24 → devhive-0.1.25}/LICENSE +0 -0
  9. {devhive-0.1.24 → devhive-0.1.25}/MANIFEST.in +0 -0
  10. {devhive-0.1.24 → devhive-0.1.25}/community_skills/architecture-patterns/SKILL.md +0 -0
  11. {devhive-0.1.24 → devhive-0.1.25}/community_skills/architecture-patterns/resources/implementation-playbook.md +0 -0
  12. {devhive-0.1.24 → devhive-0.1.25}/community_skills/backend-arthitect/SKILL.md +0 -0
  13. {devhive-0.1.24 → devhive-0.1.25}/community_skills/backend-security-coder/SKILL.md +0 -0
  14. {devhive-0.1.24 → devhive-0.1.25}/community_skills/docker-expert/SKILL.md +0 -0
  15. {devhive-0.1.24 → devhive-0.1.25}/community_skills/frontend-design/SKILL.md +0 -0
  16. {devhive-0.1.24 → devhive-0.1.25}/community_skills/frontend-developer/SKILL.md +0 -0
  17. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/SKILL.md +0 -0
  18. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/theme-showcase.pdf +0 -0
  19. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/arctic-frost.md +0 -0
  20. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/botanical-garden.md +0 -0
  21. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/desert-rose.md +0 -0
  22. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/forest-canopy.md +0 -0
  23. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/golden-hour.md +0 -0
  24. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/midnight-galaxy.md +0 -0
  25. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/modern-minimalist.md +0 -0
  26. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/ocean-depths.md +0 -0
  27. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/sunset-boulevard.md +0 -0
  28. {devhive-0.1.24 → devhive-0.1.25}/community_skills/theme-factory/themes/tech-innovation.md +0 -0
  29. {devhive-0.1.24 → devhive-0.1.25}/devhive.egg-info/dependency_links.txt +0 -0
  30. {devhive-0.1.24 → devhive-0.1.25}/devhive.egg-info/entry_points.txt +0 -0
  31. {devhive-0.1.24 → devhive-0.1.25}/devhive.egg-info/requires.txt +0 -0
  32. {devhive-0.1.24 → devhive-0.1.25}/devhive.egg-info/top_level.txt +0 -0
  33. {devhive-0.1.24 → devhive-0.1.25}/devhive_cli/__init__.py +0 -0
  34. {devhive-0.1.24 → devhive-0.1.25}/setup.cfg +0 -0
  35. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_architect/SKILL.md +0 -0
  36. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_auditor/SKILL.md +0 -0
  37. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_backender/SKILL.md +0 -0
  38. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_dba/SKILL.md +0 -0
  39. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_designer/SKILL.md +0 -0
  40. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_devops/SKILL.md +0 -0
  41. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_explorer/SKILL.md +0 -0
  42. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_frontender/SKILL.md +0 -0
  43. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_orchestrator/SKILL.md +0 -0
  44. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_perf/SKILL.md +0 -0
  45. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_proposal/SKILL.md +0 -0
  46. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_qa/SKILL.md +0 -0
  47. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_releaser/SKILL.md +0 -0
  48. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_sast/SKILL.md +0 -0
  49. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_taskplanner/SKILL.md +0 -0
  50. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_techwriter/SKILL.md +0 -0
  51. {devhive-0.1.24 → devhive-0.1.25}/skills/devhive_workflow.md +0 -0
  52. {devhive-0.1.24 → devhive-0.1.25}/templates/AGENTS.frontend.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devhive
3
- Version: 0.1.24
3
+ Version: 0.1.25
4
4
  Summary: CLI to manage DevHive skills and autonomous AI agents for OpenCode.
5
5
  Home-page: https://github.com/ramBlanco/devhive
6
6
  Author: ramBlanco
@@ -68,6 +68,9 @@ devhive update-skill
68
68
 
69
69
  # Initialize a modern Next.js/React frontend AI guidelines file in your current project
70
70
  devhive init-frontend
71
+
72
+ # Initialize a Hexagonal Architecture backend AI guidelines file (Interactive Prompt)
73
+ devhive init-backend
71
74
  ```
72
75
 
73
76
  ## Usage (The `@devhive` Agent)
@@ -45,6 +45,9 @@ devhive update-skill
45
45
 
46
46
  # Initialize a modern Next.js/React frontend AI guidelines file in your current project
47
47
  devhive init-frontend
48
+
49
+ # Initialize a Hexagonal Architecture backend AI guidelines file (Interactive Prompt)
50
+ devhive init-backend
48
51
  ```
49
52
 
50
53
  ## Usage (The `@devhive` Agent)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devhive
3
- Version: 0.1.24
3
+ Version: 0.1.25
4
4
  Summary: CLI to manage DevHive skills and autonomous AI agents for OpenCode.
5
5
  Home-page: https://github.com/ramBlanco/devhive
6
6
  Author: ramBlanco
@@ -68,6 +68,9 @@ devhive update-skill
68
68
 
69
69
  # Initialize a modern Next.js/React frontend AI guidelines file in your current project
70
70
  devhive init-frontend
71
+
72
+ # Initialize a Hexagonal Architecture backend AI guidelines file (Interactive Prompt)
73
+ devhive init-backend
71
74
  ```
72
75
 
73
76
  ## Usage (The `@devhive` Agent)
@@ -29,6 +29,7 @@ devhive.egg-info/requires.txt
29
29
  devhive.egg-info/top_level.txt
30
30
  devhive_cli/__init__.py
31
31
  devhive_cli/main.py
32
+ devhive_cli/templates_backend.py
32
33
  skills/devhive_workflow.md
33
34
  skills/devhive_architect/SKILL.md
34
35
  skills/devhive_auditor/SKILL.md
@@ -3,6 +3,7 @@ import shutil
3
3
  import subprocess
4
4
  from pathlib import Path
5
5
  import click
6
+ from devhive_cli.templates_backend import generate_backend_agents_md
6
7
 
7
8
  # Paths configuration
8
9
  CLI_DIR = Path(__file__).resolve().parent
@@ -93,5 +94,33 @@ def init_frontend():
93
94
  shutil.copy2(template_path, dest_path)
94
95
  click.secho("✅ Successfully created AGENTS.md with modern Next.js/React frontend guidelines!", fg="green", bold=True)
95
96
 
97
+ @cli.command()
98
+ def init_backend():
99
+ """Initialize a modern backend AGENTS.md template with Hexagonal Architecture."""
100
+ dest_path = Path.cwd() / "AGENTS.md"
101
+
102
+ if dest_path.exists():
103
+ click.secho("AGENTS.md already exists in this directory. Aborting to prevent overwrite.", fg="yellow")
104
+ return
105
+
106
+ language = click.prompt("Which backend language?", type=click.Choice(['python', 'node']))
107
+
108
+ use_di = False
109
+ if language == 'python':
110
+ framework = click.prompt("Which framework?", type=click.Choice(['fastapi', 'django', 'none']))
111
+ else:
112
+ framework = click.prompt("Which framework?", type=click.Choice(['express', 'nestjs', 'none']))
113
+ if framework != 'nestjs':
114
+ use_di = click.confirm("Do you want to use InversifyJS for Dependency Injection?")
115
+
116
+ iac = click.prompt("Which IaC tool are you using?", type=click.Choice(['cdk', 'terraform', 'serverless']))
117
+
118
+ md_content = generate_backend_agents_md(language, framework, iac, use_di)
119
+
120
+ with open(dest_path, "w", encoding="utf-8") as f:
121
+ f.write(md_content)
122
+
123
+ click.secho("✅ Successfully created AGENTS.md with Hexagonal Architecture guidelines!", fg="green", bold=True)
124
+
96
125
  if __name__ == "__main__":
97
126
  cli()
@@ -0,0 +1,424 @@
1
+ def generate_backend_agents_md(language: str, framework: str, iac: str, use_di: bool) -> str:
2
+ stack_list = []
3
+ if language == 'python':
4
+ stack_list.append("- **Language**: Python 3.10+ (Strict Type Hinting)")
5
+ if framework == 'fastapi':
6
+ stack_list.append("- **Framework**: FastAPI")
7
+ elif framework == 'django':
8
+ stack_list.append("- **Framework**: Django")
9
+ else:
10
+ stack_list.append("- **Framework**: None (Pure Python / Lambdas)")
11
+ else:
12
+ stack_list.append("- **Language**: Node.js + TypeScript (Strict Mode)")
13
+ if framework == 'express':
14
+ stack_list.append("- **Framework**: Express")
15
+ elif framework == 'nestjs':
16
+ stack_list.append("- **Framework**: NestJS (Built-in DI)")
17
+ use_di = False # NestJS has its own DI
18
+ else:
19
+ stack_list.append("- **Framework**: None (Pure Node.js / Lambdas)")
20
+
21
+ if use_di:
22
+ stack_list.append("- **Dependency Injection**: InversifyJS")
23
+
24
+ if iac == 'cdk':
25
+ stack_list.append("- **Infrastructure as Code**: AWS CDK")
26
+ elif iac == 'terraform':
27
+ stack_list.append("- **Infrastructure as Code**: Terraform")
28
+ else:
29
+ stack_list.append("- **Infrastructure as Code**: Serverless Framework")
30
+
31
+ stack_section = "\n".join(stack_list)
32
+
33
+ # Base structure
34
+ md = f"""# Backend Architecture & AI Agent Guidelines
35
+
36
+ This `AGENTS.md` (or `GUIDELINES.md`) file serves as the strict instruction manual for OpenCode and DevHive agents. It defines the technical stack, architectural patterns, and coding conventions for this backend project.
37
+
38
+ ## 🛠️ 1. Tech Stack
39
+ {stack_section}
40
+
41
+ ## 🧠 2. OpenCode Skills to Load
42
+ Agents **MUST** load the following specialized skills before executing tasks:
43
+ - `architecture-patterns`: For maintaining clean separation of concerns and Hexagonal Architecture.
44
+ - `backend-architect`: For scalable API design and domain modeling.
45
+ - `backend-security-coder`: For secure coding practices, input validation, and auth.
46
+ - `devhive-devops`: For {iac.upper()} infrastructure setup.
47
+
48
+ ## 📂 3. Project Structure (Hexagonal Architecture)
49
+ For maximum scalability, testability, and maintainability, the project MUST strictly follow Hexagonal Architecture (Ports & Adapters).
50
+
51
+ ```text
52
+ src/
53
+ ├── domain/ # ENTERPRISE BUSINESS RULES (No external dependencies)
54
+ │ ├── entities/ # Pure domain models
55
+ │ └── exceptions/ # Domain-specific errors
56
+ ├── application/ # APPLICATION BUSINESS RULES (Use Cases & Ports)
57
+ │ ├── use_cases/ # Orchestrates domain logic
58
+ │ └── ports/ # Interfaces for outbound communication (Repositories, External APIs)
59
+ ├── infrastructure/ # ADAPTERS (Database, External Services, Third-party libs)
60
+ │ ├── database/ # Concrete implementation of repository ports
61
+ │ └── di/ # Dependency Injection container/setup
62
+ └── presentation/ # ENTRY POINTS (Controllers, REST APIs, GraphQL, Lambdas)
63
+ └── controllers/ # Parses HTTP requests and calls use cases
64
+
65
+ infrastructure/ # IaC DEFINITIONS (Outside src/)
66
+ └── # {iac.upper()} configurations
67
+ ```
68
+
69
+ ## 📐 4. Architectural Rules & Clean Code (CRITICAL)
70
+
71
+ 1. **The Dependency Rule**: Source code dependencies MUST only point inward, toward the `domain/`.
72
+ - `domain/` knows nothing about anything else.
73
+ - `application/` depends only on `domain/`.
74
+ - `infrastructure/` and `presentation/` depend on `application/` and `domain/`.
75
+ - **Never import an infrastructure detail (like a DB model) into a use case.**
76
+
77
+ 2. **Ports and Adapters**:
78
+ - Outbound communication (like DB queries) MUST be defined as an interface (Port) in the `application/` layer.
79
+ - The actual database logic MUST be implemented as an Adapter in the `infrastructure/` layer.
80
+
81
+ 3. **Dependency Injection**:
82
+ - Use Cases must receive their dependencies (Ports) via constructor injection.
83
+ - The Presentation layer resolves these dependencies and passes them to the Use Cases.
84
+ """
85
+
86
+ if language == 'node' and use_di:
87
+ md += """
88
+ 4. **InversifyJS Usage**:
89
+ - Decorate concrete adapters in `infrastructure/` with `@injectable()`.
90
+ - Bind interfaces to symbols in an `inversify.config.ts` container file.
91
+ - Use the container in the `presentation/` layer to resolve use cases.
92
+ """
93
+
94
+ md += "\n## 💻 5. Code Examples\n\n"
95
+
96
+ if language == 'python':
97
+ if framework == 'fastapi':
98
+ md += """### Example: FastAPI + Hexagonal Architecture
99
+
100
+ **1. Port (Application Layer)**
101
+ *File: `src/application/ports/user_repository.py`*
102
+ ```python
103
+ from typing import Protocol
104
+ from src.domain.entities.user import User
105
+
106
+ class UserRepository(Protocol):
107
+ def get_by_id(self, user_id: str) -> User | None:
108
+ ...
109
+ ```
110
+
111
+ **2. Adapter (Infrastructure Layer)**
112
+ *File: `src/infrastructure/database/postgres_user_repository.py`*
113
+ ```python
114
+ from src.application.ports.user_repository import UserRepository
115
+ from src.domain.entities.user import User
116
+
117
+ class PostgresUserRepository:
118
+ def __init__(self, db_session):
119
+ self.db = db_session
120
+
121
+ def get_by_id(self, user_id: str) -> User | None:
122
+ # DB logic here returning Domain Entity
123
+ return User(id=user_id, name="Alice")
124
+ ```
125
+
126
+ **3. Use Case (Application Layer)**
127
+ *File: `src/application/use_cases/get_user.py`*
128
+ ```python
129
+ from src.application.ports.user_repository import UserRepository
130
+ from src.domain.entities.user import User
131
+ from src.domain.exceptions import UserNotFoundError
132
+
133
+ class GetUserUseCase:
134
+ def __init__(self, user_repo: UserRepository):
135
+ self.user_repo = user_repo
136
+
137
+ def execute(self, user_id: str) -> User:
138
+ user = self.user_repo.get_by_id(user_id)
139
+ if not user:
140
+ raise UserNotFoundError(f"User {user_id} not found")
141
+ return user
142
+ ```
143
+
144
+ **4. Controller (Presentation Layer)**
145
+ *File: `src/presentation/controllers/user_controller.py`*
146
+ ```python
147
+ from fastapi import APIRouter, Depends, HTTPException
148
+ from src.application.use_cases.get_user import GetUserUseCase
149
+ from src.infrastructure.database.postgres_user_repository import PostgresUserRepository
150
+ from src.domain.exceptions import UserNotFoundError
151
+
152
+ router = APIRouter()
153
+
154
+ # Poor man's DI for FastAPI
155
+ def get_user_use_case() -> GetUserUseCase:
156
+ repo = PostgresUserRepository(db_session=None)
157
+ return GetUserUseCase(user_repo=repo)
158
+
159
+ @router.get("/users/{user_id}")
160
+ def get_user(user_id: str, use_case: GetUserUseCase = Depends(get_user_use_case)):
161
+ try:
162
+ return use_case.execute(user_id)
163
+ except UserNotFoundError as e:
164
+ raise HTTPException(status_code=404, detail=str(e))
165
+ ```
166
+ """
167
+ elif framework == 'django':
168
+ md += """### Example: Django + Hexagonal Architecture
169
+
170
+ **Note on Django**: Do NOT put business logic in Django Views or Models. Use Django ONLY as the `infrastructure/` and `presentation/` layers.
171
+
172
+ **1. Port (Application Layer)**
173
+ *File: `src/application/ports/user_repository.py`*
174
+ ```python
175
+ import abc
176
+ from src.domain.entities.user import User
177
+
178
+ class UserRepository(abc.ABC):
179
+ @abc.abstractmethod
180
+ def get_by_id(self, user_id: str) -> User | None:
181
+ pass
182
+ ```
183
+
184
+ **2. Adapter (Infrastructure Layer)**
185
+ *File: `src/infrastructure/database/django_user_repository.py`*
186
+ ```python
187
+ from src.application.ports.user_repository import UserRepository
188
+ from src.domain.entities.user import User
189
+ from myapp.models import DjangoUserModel # Django ORM Model
190
+
191
+ class DjangoUserRepository(UserRepository):
192
+ def get_by_id(self, user_id: str) -> User | None:
193
+ try:
194
+ orm_user = DjangoUserModel.objects.get(id=user_id)
195
+ return User(id=str(orm_user.id), name=orm_user.name) # Map ORM to Domain
196
+ except DjangoUserModel.DoesNotExist:
197
+ return None
198
+ ```
199
+
200
+ **3. Controller (Presentation Layer)**
201
+ *File: `src/presentation/views/user_views.py`*
202
+ ```python
203
+ from django.http import JsonResponse
204
+ from src.application.use_cases.get_user import GetUserUseCase
205
+ from src.infrastructure.database.django_user_repository import DjangoUserRepository
206
+ from src.domain.exceptions import UserNotFoundError
207
+
208
+ def get_user_view(request, user_id: str):
209
+ repo = DjangoUserRepository()
210
+ use_case = GetUserUseCase(user_repo=repo)
211
+
212
+ try:
213
+ user = use_case.execute(user_id)
214
+ return JsonResponse({"id": user.id, "name": user.name})
215
+ except UserNotFoundError as e:
216
+ return JsonResponse({"error": str(e)}, status=404)
217
+ ```
218
+ """
219
+ else:
220
+ md += """### Example: Pure Python + Hexagonal Architecture
221
+
222
+ **1. Port (Application Layer)**
223
+ *File: `src/application/ports/user_repository.py`*
224
+ ```python
225
+ from typing import Protocol
226
+ from src.domain.entities.user import User
227
+
228
+ class UserRepository(Protocol):
229
+ def get_by_id(self, user_id: str) -> User | None:
230
+ ...
231
+ ```
232
+
233
+ **2. Use Case (Application Layer)**
234
+ *File: `src/application/use_cases/get_user.py`*
235
+ ```python
236
+ from src.application.ports.user_repository import UserRepository
237
+ from src.domain.entities.user import User
238
+
239
+ class GetUserUseCase:
240
+ def __init__(self, user_repo: UserRepository):
241
+ self.user_repo = user_repo
242
+
243
+ def execute(self, user_id: str) -> User:
244
+ return self.user_repo.get_by_id(user_id)
245
+ ```
246
+
247
+ **3. Handler (Presentation Layer - Lambda)**
248
+ *File: `src/presentation/handlers/user_handler.py`*
249
+ ```python
250
+ from src.application.use_cases.get_user import GetUserUseCase
251
+ from src.infrastructure.database.dynamo_user_repository import DynamoUserRepository
252
+
253
+ # Initialize dependencies at the module level for Lambda cold starts
254
+ repo = DynamoUserRepository()
255
+ use_case = GetUserUseCase(user_repo=repo)
256
+
257
+ def lambda_handler(event, context):
258
+ user_id = event.get('pathParameters', {}).get('userId')
259
+ user = use_case.execute(user_id)
260
+ return {"statusCode": 200, "body": user.to_json()}
261
+ ```
262
+ """
263
+ else: # Node.js
264
+ if use_di:
265
+ md += """### Example: Node.js + TypeScript + InversifyJS
266
+
267
+ **1. Port (Application Layer)**
268
+ *File: `src/application/ports/IUserRepository.ts`*
269
+ ```typescript
270
+ import { User } from "../../domain/entities/User";
271
+
272
+ export const TYPES = {
273
+ IUserRepository: Symbol.for("IUserRepository"),
274
+ GetUserUseCase: Symbol.for("GetUserUseCase"),
275
+ };
276
+
277
+ export interface IUserRepository {
278
+ getById(userId: string): Promise<User | null>;
279
+ }
280
+ ```
281
+
282
+ **2. Adapter (Infrastructure Layer)**
283
+ *File: `src/infrastructure/database/PostgresUserRepository.ts`*
284
+ ```typescript
285
+ import { injectable } from "inversify";
286
+ import "reflect-metadata";
287
+ import { IUserRepository } from "../../application/ports/IUserRepository";
288
+ import { User } from "../../domain/entities/User";
289
+
290
+ @injectable()
291
+ export class PostgresUserRepository implements IUserRepository {
292
+ async getById(userId: string): Promise<User | null> {
293
+ // DB Logic returning Domain Entity
294
+ return new User(userId, "Alice");
295
+ }
296
+ }
297
+ ```
298
+
299
+ **3. Use Case (Application Layer)**
300
+ *File: `src/application/useCases/GetUserUseCase.ts`*
301
+ ```typescript
302
+ import { inject, injectable } from "inversify";
303
+ import "reflect-metadata";
304
+ import { IUserRepository, TYPES } from "../ports/IUserRepository";
305
+ import { User } from "../../domain/entities/User";
306
+
307
+ @injectable()
308
+ export class GetUserUseCase {
309
+ constructor(
310
+ @inject(TYPES.IUserRepository) private userRepository: IUserRepository
311
+ ) {}
312
+
313
+ async execute(userId: string): Promise<User> {
314
+ const user = await this.userRepository.getById(userId);
315
+ if (!user) throw new Error("User not found");
316
+ return user;
317
+ }
318
+ }
319
+ ```
320
+
321
+ **4. DI Container Setup (Infrastructure Layer)**
322
+ *File: `src/infrastructure/di/container.ts`*
323
+ ```typescript
324
+ import { Container } from "inversify";
325
+ import { TYPES, IUserRepository } from "../../application/ports/IUserRepository";
326
+ import { PostgresUserRepository } from "../database/PostgresUserRepository";
327
+ import { GetUserUseCase } from "../../application/useCases/GetUserUseCase";
328
+
329
+ const container = new Container();
330
+
331
+ container.bind<IUserRepository>(TYPES.IUserRepository).to(PostgresUserRepository);
332
+ container.bind<GetUserUseCase>(TYPES.GetUserUseCase).to(GetUserUseCase);
333
+
334
+ export { container };
335
+ ```
336
+
337
+ **5. Controller (Presentation Layer)**
338
+ *File: `src/presentation/controllers/UserController.ts`*
339
+ ```typescript
340
+ import { Request, Response } from "express";
341
+ import { container } from "../../infrastructure/di/container";
342
+ import { TYPES } from "../../application/ports/IUserRepository";
343
+ import { GetUserUseCase } from "../../application/useCases/GetUserUseCase";
344
+
345
+ export class UserController {
346
+ async getUser(req: Request, res: Response) {
347
+ const useCase = container.get<GetUserUseCase>(TYPES.GetUserUseCase);
348
+ try {
349
+ const user = await useCase.execute(req.params.id);
350
+ res.json(user);
351
+ } catch (error) {
352
+ res.status(404).json({ error: error.message });
353
+ }
354
+ }
355
+ }
356
+ ```
357
+ """
358
+ else:
359
+ md += """### Example: Node.js + TypeScript (Manual DI)
360
+
361
+ **1. Port (Application Layer)**
362
+ *File: `src/application/ports/IUserRepository.ts`*
363
+ ```typescript
364
+ import { User } from "../../domain/entities/User";
365
+
366
+ export interface IUserRepository {
367
+ getById(userId: string): Promise<User | null>;
368
+ }
369
+ ```
370
+
371
+ **2. Adapter (Infrastructure Layer)**
372
+ *File: `src/infrastructure/database/PostgresUserRepository.ts`*
373
+ ```typescript
374
+ import { IUserRepository } from "../../application/ports/IUserRepository";
375
+ import { User } from "../../domain/entities/User";
376
+
377
+ export class PostgresUserRepository implements IUserRepository {
378
+ async getById(userId: string): Promise<User | null> {
379
+ // DB Logic returning Domain Entity
380
+ return new User(userId, "Alice");
381
+ }
382
+ }
383
+ ```
384
+
385
+ **3. Use Case (Application Layer)**
386
+ *File: `src/application/useCases/GetUserUseCase.ts`*
387
+ ```typescript
388
+ import { IUserRepository } from "../ports/IUserRepository";
389
+ import { User } from "../../domain/entities/User";
390
+
391
+ export class GetUserUseCase {
392
+ constructor(private userRepository: IUserRepository) {}
393
+
394
+ async execute(userId: string): Promise<User> {
395
+ const user = await this.userRepository.getById(userId);
396
+ if (!user) throw new Error("User not found");
397
+ return user;
398
+ }
399
+ }
400
+ ```
401
+
402
+ **4. Controller (Presentation Layer)**
403
+ *File: `src/presentation/controllers/UserController.ts`*
404
+ ```typescript
405
+ import { Request, Response } from "express";
406
+ import { GetUserUseCase } from "../../application/useCases/GetUserUseCase";
407
+ import { PostgresUserRepository } from "../../infrastructure/database/PostgresUserRepository";
408
+
409
+ export class UserController {
410
+ async getUser(req: Request, res: Response) {
411
+ const repo = new PostgresUserRepository();
412
+ const useCase = new GetUserUseCase(repo);
413
+ try {
414
+ const user = await useCase.execute(req.params.id);
415
+ res.json(user);
416
+ } catch (error) {
417
+ res.status(404).json({ error: error.message });
418
+ }
419
+ }
420
+ }
421
+ ```
422
+ """
423
+
424
+ return md
@@ -8,7 +8,7 @@ with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
8
8
 
9
9
  setup(
10
10
  name="devhive",
11
- version="0.1.24",
11
+ version="0.1.25",
12
12
  packages=find_packages(),
13
13
  include_package_data=True,
14
14
  install_requires=[
File without changes
File without changes
File without changes