├── demo-hexagonal-architecture-angular ├── .editorconfig ├── .gitignore ├── .vscode │ ├── extensions.json │ ├── launch.json │ └── tasks.json ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.ts │ │ ├── app.config.ts │ │ ├── domain │ │ │ └── product │ │ │ │ ├── application │ │ │ │ └── product-use-case.service.ts │ │ │ │ ├── domain │ │ │ │ └── product.model.ts │ │ │ │ └── infrastructure │ │ │ │ ├── models │ │ │ │ └── produc-api.model.ts │ │ │ │ ├── product-api.interface.ts │ │ │ │ ├── product-api.service.ts │ │ │ │ ├── product-delay-api.service.ts │ │ │ │ └── providers │ │ │ │ └── product-api.provider.ts │ │ └── ui │ │ │ ├── products-page │ │ │ ├── products-page.component.html │ │ │ ├── products-page.component.scss │ │ │ └── products-page.component.ts │ │ │ └── user-page │ │ │ └── .gitkeep │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.development.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ └── styles.scss ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json ├── demo-hexagonal-architecture ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── nest-cli.json ├── package-lock.json ├── package.json ├── src │ ├── app.module.ts │ ├── commons │ │ ├── domain │ │ │ ├── dto │ │ │ │ └── product-repository.dto.ts │ │ │ ├── entities │ │ │ │ ├── entity-index.ts │ │ │ │ ├── product.entity.ts │ │ │ │ └── user.entity.ts │ │ │ └── repository │ │ │ │ ├── orm-product.repositor.interface.ts │ │ │ │ └── orm-product.repository.ts │ │ └── infrastructure │ │ │ └── config-database.ts │ ├── main.ts │ └── products │ │ ├── application │ │ ├── produc-use-case.interface.ts │ │ └── product-use-case.service.ts │ │ ├── domain │ │ ├── models │ │ │ └── product-repository.model.ts │ │ └── repository │ │ │ ├── product.interface.ts │ │ │ └── product.repository.ts │ │ ├── infrastructure │ │ ├── dto │ │ │ └── product.dto.ts │ │ └── product.controller.ts │ │ └── products.module.ts ├── test │ ├── app.e2e-spec.ts │ └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json └── readme.md /demo-hexagonal-architecture-angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/README.md: -------------------------------------------------------------------------------- 1 | # ARQUITECTURA HEXAGONAL 2 | 3 | ## ¡Hola, Coders! 4 | 5 | Si crees que mis videos te ayudan a mejorar profesionalmente o aprender algo nuevo, apoyame con tu suscripción.🤗 6 | 7 | # Mis Redes 8 | 9 | **Suscríbete a mi canal** 😎 10 | 11 | **YouTube:** [LogiDev](https://www.youtube.com/@LogiDev) 12 | 13 | **Twitch:** [Jimy Dolores](https://www.twitch.tv/jimydolores) 14 | 15 | **Sígueme en mis redes:** 16 | 17 | 👉Facebook : [LogiDev](https://facebook.com/LogiDev25) 18 | 19 | búscame como: [@LogiDev25](https://facebook.com/LogiDev25) 20 | 21 | 👉Instagram: [@jimydolores](https://instagram.com/jimydolores/) 22 | 23 | 👉Twitter: [Jimy Dolores](https://twitter.com/jimydolores) 24 | 25 | 👉LinkedIn:[Jimy Dolores](https://linkedin.com/in/jimyhuachodolores/) 26 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "demo-hexagonal-architecture-angular": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss", 11 | "skipTests": true, 12 | "standalone": true 13 | }, 14 | "@schematics/angular:class": { 15 | "skipTests": true 16 | }, 17 | "@schematics/angular:directive": { 18 | "skipTests": true, 19 | "standalone": true 20 | }, 21 | "@schematics/angular:guard": { 22 | "skipTests": true 23 | }, 24 | "@schematics/angular:interceptor": { 25 | "skipTests": true 26 | }, 27 | "@schematics/angular:pipe": { 28 | "skipTests": true, 29 | "standalone": true 30 | }, 31 | "@schematics/angular:resolver": { 32 | "skipTests": true 33 | }, 34 | "@schematics/angular:service": { 35 | "skipTests": true 36 | } 37 | }, 38 | "root": "", 39 | "sourceRoot": "src", 40 | "prefix": "app", 41 | "architect": { 42 | "build": { 43 | "builder": "@angular-devkit/build-angular:browser", 44 | "options": { 45 | "outputPath": "dist/demo-hexagonal-architecture-angular", 46 | "index": "src/index.html", 47 | "main": "src/main.ts", 48 | "polyfills": [ 49 | "zone.js" 50 | ], 51 | "tsConfig": "tsconfig.app.json", 52 | "inlineStyleLanguage": "scss", 53 | "assets": [ 54 | "src/favicon.ico", 55 | "src/assets" 56 | ], 57 | "styles": [ 58 | "@angular/material/prebuilt-themes/deeppurple-amber.css", 59 | "src/styles.scss" 60 | ], 61 | "scripts": [] 62 | }, 63 | "configurations": { 64 | "production": { 65 | "budgets": [ 66 | { 67 | "type": "initial", 68 | "maximumWarning": "500kb", 69 | "maximumError": "1mb" 70 | }, 71 | { 72 | "type": "anyComponentStyle", 73 | "maximumWarning": "2kb", 74 | "maximumError": "4kb" 75 | } 76 | ], 77 | "outputHashing": "all" 78 | }, 79 | "development": { 80 | "buildOptimizer": false, 81 | "optimization": false, 82 | "vendorChunk": true, 83 | "extractLicenses": false, 84 | "sourceMap": true, 85 | "namedChunks": true, 86 | "fileReplacements": [ 87 | { 88 | "replace": "src/environments/environment.ts", 89 | "with": "src/environments/environment.development.ts" 90 | } 91 | ] 92 | } 93 | }, 94 | "defaultConfiguration": "production" 95 | }, 96 | "serve": { 97 | "builder": "@angular-devkit/build-angular:dev-server", 98 | "configurations": { 99 | "production": { 100 | "browserTarget": "demo-hexagonal-architecture-angular:build:production" 101 | }, 102 | "development": { 103 | "browserTarget": "demo-hexagonal-architecture-angular:build:development" 104 | } 105 | }, 106 | "defaultConfiguration": "development" 107 | }, 108 | "extract-i18n": { 109 | "builder": "@angular-devkit/build-angular:extract-i18n", 110 | "options": { 111 | "browserTarget": "demo-hexagonal-architecture-angular:build" 112 | } 113 | }, 114 | "test": { 115 | "builder": "@angular-devkit/build-angular:karma", 116 | "options": { 117 | "polyfills": [ 118 | "zone.js", 119 | "zone.js/testing" 120 | ], 121 | "tsConfig": "tsconfig.spec.json", 122 | "inlineStyleLanguage": "scss", 123 | "assets": [ 124 | "src/favicon.ico", 125 | "src/assets" 126 | ], 127 | "styles": [ 128 | "@angular/material/prebuilt-themes/deeppurple-amber.css", 129 | "src/styles.scss" 130 | ], 131 | "scripts": [] 132 | } 133 | } 134 | } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-hexagonal-architecture-angular", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^16.1.0", 14 | "@angular/cdk": "^16.1.2", 15 | "@angular/common": "^16.1.0", 16 | "@angular/compiler": "^16.1.0", 17 | "@angular/core": "^16.1.0", 18 | "@angular/forms": "^16.1.0", 19 | "@angular/material": "^16.1.2", 20 | "@angular/platform-browser": "^16.1.0", 21 | "@angular/platform-browser-dynamic": "^16.1.0", 22 | "@angular/router": "^16.1.0", 23 | "rxjs": "~7.8.0", 24 | "tslib": "^2.3.0", 25 | "zone.js": "~0.13.0" 26 | }, 27 | "devDependencies": { 28 | "@angular-devkit/build-angular": "^16.1.0", 29 | "@angular/cli": "~16.1.0", 30 | "@angular/compiler-cli": "^16.1.0", 31 | "@types/jasmine": "~4.3.0", 32 | "jasmine-core": "~4.6.0", 33 | "karma": "~6.4.0", 34 | "karma-chrome-launcher": "~3.2.0", 35 | "karma-coverage": "~2.2.0", 36 | "karma-jasmine": "~5.1.0", 37 | "karma-jasmine-html-reporter": "~2.1.0", 38 | "typescript": "~5.1.3" 39 | } 40 | } -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ProductsPageComponent } from './ui/products-page/products-page.component'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | standalone: true, 7 | template: ``, 8 | imports: [ProductsPageComponent] 9 | }) 10 | export class AppComponent {} 11 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/app.config.ts: -------------------------------------------------------------------------------- 1 | import { provideHttpClient } from '@angular/common/http'; 2 | import { ApplicationConfig } from '@angular/core'; 3 | import { provideAnimations } from '@angular/platform-browser/animations'; 4 | import { PRODUCT_API_PROVIDER } from './domain/product/infrastructure/providers/product-api.provider'; 5 | 6 | export const appConfig: ApplicationConfig = { 7 | providers: [provideAnimations(), provideHttpClient(), PRODUCT_API_PROVIDER] 8 | }; 9 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/domain/product/application/product-use-case.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import { IDomainRequestProduct, IDomainResponse } from '../domain/product.model'; 4 | import { IProductApiService } from '../infrastructure/product-api.interface'; 5 | import { HTTP_PRODUCT_SERVICE } from '../infrastructure/providers/product-api.provider'; 6 | 7 | @Injectable({ providedIn: 'root' }) 8 | export class ProductUseCaseService { 9 | constructor(@Inject(HTTP_PRODUCT_SERVICE) private _productApiService: IProductApiService) {} 10 | 11 | getProducts(): Observable { 12 | //TODO: aplicar logica 13 | return this._productApiService.getProducts(); 14 | } 15 | 16 | saveProduct(newProduct: IDomainRequestProduct): Observable { 17 | return this._productApiService.save(newProduct); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/domain/product/domain/product.model.ts: -------------------------------------------------------------------------------- 1 | export interface IDomainRequestProduct { 2 | description: string; 3 | price: number; 4 | } 5 | 6 | export interface IDomainResponseProduct extends IDomainRequestProduct { 7 | productId: number; 8 | } 9 | 10 | export interface IDomainResponse { 11 | message: string; 12 | code: number; 13 | } 14 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/domain/product/infrastructure/models/produc-api.model.ts: -------------------------------------------------------------------------------- 1 | export interface IApiRequestProduct { 2 | readonly description: string; 3 | readonly price: number; 4 | } 5 | 6 | export interface IApiResponseProduct extends IApiRequestProduct { 7 | readonly productId: number; 8 | } 9 | 10 | export interface IApiResponse { 11 | readonly message: string; 12 | readonly code: number; 13 | } 14 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/domain/product/infrastructure/product-api.interface.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { IDomainRequestProduct, IDomainResponse } from '../domain/product.model'; 3 | 4 | export interface IProductApiService { 5 | getProducts(): Observable; 6 | save(newProduct: IDomainRequestProduct): Observable; 7 | } 8 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/domain/product/infrastructure/product-api.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable, inject } from '@angular/core'; 3 | import { Observable, map } from 'rxjs'; 4 | import { environment } from '../../../../environments/environment'; 5 | import { IDomainRequestProduct, IDomainResponse, IDomainResponseProduct } from '../domain/product.model'; 6 | import { IApiResponse, IApiResponseProduct } from './models/produc-api.model'; 7 | import { IProductApiService } from './product-api.interface'; 8 | 9 | @Injectable() 10 | export class ProductApiService implements IProductApiService { 11 | private _httpClient = inject(HttpClient); 12 | private readonly URL_PRODUCTS = environment.api + '/product'; 13 | 14 | getProducts(): Observable { 15 | return this._httpClient.get(this.URL_PRODUCTS).pipe( 16 | map((response) => 17 | response.map((productApi) => ({ 18 | productId: productApi.productId, 19 | description: productApi.description, 20 | price: productApi.price 21 | })) 22 | ) 23 | ); 24 | } 25 | 26 | save(newProduct: IDomainRequestProduct): Observable { 27 | return this._httpClient 28 | .post(this.URL_PRODUCTS, newProduct) 29 | .pipe(map((response) => ({ message: response.message, code: response.code }))); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/domain/product/infrastructure/product-delay-api.service.ts: -------------------------------------------------------------------------------- 1 | import { HttpClient } from '@angular/common/http'; 2 | import { Injectable, inject } from '@angular/core'; 3 | import { Observable, delay, map } from 'rxjs'; 4 | import { environment } from '../../../../environments/environment'; 5 | import { IDomainRequestProduct, IDomainResponse, IDomainResponseProduct } from '../domain/product.model'; 6 | import { IApiResponse, IApiResponseProduct } from './models/produc-api.model'; 7 | import { IProductApiService } from './product-api.interface'; 8 | 9 | @Injectable() 10 | export class ProductDelayApiService implements IProductApiService { 11 | private _httpClient = inject(HttpClient); 12 | private readonly URL_PRODUCTS = environment.api + '/product'; 13 | 14 | getProducts(): Observable { 15 | return this._httpClient.get(this.URL_PRODUCTS).pipe( 16 | delay(2000), 17 | map((response) => 18 | response.map((productApi) => ({ 19 | productId: productApi.productId, 20 | description: productApi.description, 21 | price: productApi.price 22 | })) 23 | ) 24 | ); 25 | } 26 | 27 | save(newProduct: IDomainRequestProduct): Observable { 28 | return this._httpClient 29 | .post(this.URL_PRODUCTS, newProduct) 30 | .pipe(map((response) => ({ message: response.message, code: response.code }))); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/domain/product/infrastructure/providers/product-api.provider.ts: -------------------------------------------------------------------------------- 1 | import { InjectionToken, Provider } from '@angular/core'; 2 | import { IProductApiService } from '../product-api.interface'; 3 | import { ProductApiService } from '../product-api.service'; 4 | // import { ProductDelayApiService } from './product-delay-api.service'; 5 | 6 | export const HTTP_PRODUCT_SERVICE = new InjectionToken('ProductApiService'); 7 | 8 | export const PRODUCT_API_PROVIDER: Provider = { provide: HTTP_PRODUCT_SERVICE, useClass: ProductApiService }; 9 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/ui/products-page/products-page.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Productos

3 |
4 | 5 | Producto 6 | 7 | 8 | 9 | 10 | Precio 11 | 12 | 13 | 14 | 15 |
16 |
17 |

Listado de productos

18 | 19 | 20 | {{ product.description }} 21 | 22 |
23 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/ui/products-page/products-page.component.scss: -------------------------------------------------------------------------------- 1 | .pp-container { 2 | display: flex; 3 | flex-direction: column; 4 | 5 | padding: 2em; 6 | 7 | .pp-form { 8 | display: flex; 9 | flex-direction: column; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/ui/products-page/products-page.component.ts: -------------------------------------------------------------------------------- 1 | import { NgFor, NgIf } from '@angular/common'; 2 | import { Component, OnInit, inject } from '@angular/core'; 3 | import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; 4 | import { MatButtonModule } from '@angular/material/button'; 5 | import { MatFormFieldModule } from '@angular/material/form-field'; 6 | import { MatInputModule } from '@angular/material/input'; 7 | import { MatListModule } from '@angular/material/list'; 8 | import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; 9 | import { finalize } from 'rxjs'; 10 | import { ProductUseCaseService } from '../../domain/product/application/product-use-case.service'; 11 | import { IDomainRequestProduct } from '../../domain/product/domain/product.model'; 12 | 13 | @Component({ 14 | selector: 'app-products-page', 15 | standalone: true, 16 | imports: [ 17 | MatFormFieldModule, 18 | MatListModule, 19 | MatButtonModule, 20 | MatInputModule, 21 | ReactiveFormsModule, 22 | MatProgressSpinnerModule, 23 | NgIf, 24 | NgFor 25 | ], 26 | templateUrl: './products-page.component.html', 27 | styleUrls: ['./products-page.component.scss'] 28 | }) 29 | export class ProductsPageComponent implements OnInit { 30 | private _formBuilder = inject(FormBuilder); 31 | private _productUseCaseService = inject(ProductUseCaseService); 32 | 33 | formProduct = this._formBuilder.nonNullable.group({ 34 | description: ['', Validators.required], 35 | price: [0, Validators.required] 36 | }); 37 | 38 | listProducts: IDomainRequestProduct[] = []; 39 | showSpinner = true; 40 | 41 | ngOnInit(): void { 42 | this._loadProducts(); 43 | } 44 | 45 | saveProduct() { 46 | if (this.formProduct.valid) { 47 | this._productUseCaseService.saveProduct(this.formProduct.getRawValue()).subscribe({ 48 | next: () => { 49 | console.info('Producto guardado!!!'); 50 | this._loadProducts(); 51 | } 52 | }); 53 | } 54 | } 55 | 56 | private _loadProducts(): void { 57 | this._productUseCaseService 58 | .getProducts() 59 | .pipe(finalize(() => (this.showSpinner = false))) 60 | .subscribe({ 61 | next: (response) => { 62 | this.listProducts = response; 63 | } 64 | }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/app/ui/user-page/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimyhdolores/hexagonal-architecture-nestjs-angular/b25b736080ad420936945714b6886eb151df5120/demo-hexagonal-architecture-angular/src/app/ui/user-page/.gitkeep -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimyhdolores/hexagonal-architecture-nestjs-angular/b25b736080ad420936945714b6886eb151df5120/demo-hexagonal-architecture-angular/src/assets/.gitkeep -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/environments/environment.development.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | api: 'http://localhost:3000' 3 | }; 4 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | api: 'http://localhost:3000' 3 | }; 4 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimyhdolores/hexagonal-architecture-nestjs-angular/b25b736080ad420936945714b6886eb151df5120/demo-hexagonal-architecture-angular/src/favicon.ico -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DemoHexagonalArchitectureAngular 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/main.ts: -------------------------------------------------------------------------------- 1 | import { bootstrapApplication } from '@angular/platform-browser'; 2 | import { appConfig } from './app/app.config'; 3 | import { AppComponent } from './app/app.component'; 4 | 5 | bootstrapApplication(AppComponent, appConfig) 6 | .catch((err) => console.error(err)); 7 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { height: 100%; } 4 | body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; } 5 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "lib": [ 23 | "ES2022", 24 | "dom" 25 | ] 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture-angular/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir: __dirname, 6 | sourceType: 'module' 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], 10 | root: true, 11 | env: { 12 | node: true, 13 | jest: true 14 | }, 15 | ignorePatterns: ['.eslintrc.js'], 16 | rules: { 17 | '@typescript-eslint/interface-name-prefix': 'off', 18 | '@typescript-eslint/explicit-function-return-type': 'off', 19 | '@typescript-eslint/explicit-module-boundary-types': 'off', 20 | '@typescript-eslint/no-explicit-any': 'off' 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | pnpm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json -------------------------------------------------------------------------------- /demo-hexagonal-architecture/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "bracketSpacing": true, 4 | "insertPragma": false, 5 | "printWidth": 120, 6 | "proseWrap": "preserve", 7 | "quoteProps": "as-needed", 8 | "requirePragma": false, 9 | "semi": true, 10 | "singleQuote": true, 11 | "tabWidth": 2, 12 | "trailingComma": "none", 13 | "useTabs": true, 14 | "endOfLine": "auto" 15 | } 16 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/README.md: -------------------------------------------------------------------------------- 1 | # ARQUITECTURA HEXAGONAL 2 | 3 | ## ¡Hola, Coders! 4 | 5 | Si crees que mis videos te ayudan a mejorar profesionalmente o aprender algo nuevo, apoyame con tu suscripción.🤗 6 | 7 | # Mis Redes 8 | 9 | **Suscríbete a mi canal** 😎 10 | 11 | **YouTube:** [LogiDev](https://www.youtube.com/@LogiDev) 12 | 13 | **Twitch:** [Jimy Dolores](https://www.twitch.tv/jimydolores) 14 | 15 | **Sígueme en mis redes:** 16 | 17 | 👉Facebook : [LogiDev](https://facebook.com/LogiDev25) 18 | 19 | búscame como: [@LogiDev25](https://facebook.com/LogiDev25) 20 | 21 | 👉Instagram: [@jimydolores](https://instagram.com/jimydolores/) 22 | 23 | 👉Twitter: [Jimy Dolores](https://twitter.com/jimydolores) 24 | 25 | 👉LinkedIn:[Jimy Dolores](https://linkedin.com/in/jimyhuachodolores/) 26 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "compilerOptions": { 6 | "deleteOutDir": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-hexagonal-architecture", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "private": true, 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "build": "nest build", 10 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 11 | "start": "nest start", 12 | "start:dev": "nest start --watch", 13 | "start:debug": "nest start --debug --watch", 14 | "start:prod": "node dist/main", 15 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "test:cov": "jest --coverage", 19 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 20 | "test:e2e": "jest --config ./test/jest-e2e.json" 21 | }, 22 | "dependencies": { 23 | "@nestjs/common": "^10.0.0", 24 | "@nestjs/core": "^10.0.0", 25 | "@nestjs/platform-express": "^10.0.0", 26 | "@nestjs/typeorm": "^10.0.0", 27 | "mysql2": "^3.4.2", 28 | "reflect-metadata": "^0.1.13", 29 | "rxjs": "^7.8.1", 30 | "typeorm": "^0.3.17" 31 | }, 32 | "devDependencies": { 33 | "@nestjs/cli": "^10.0.0", 34 | "@nestjs/schematics": "^10.0.0", 35 | "@nestjs/testing": "^10.0.0", 36 | "@types/express": "^4.17.17", 37 | "@types/jest": "^29.5.2", 38 | "@types/node": "^20.3.1", 39 | "@types/supertest": "^2.0.12", 40 | "@typescript-eslint/eslint-plugin": "^5.59.11", 41 | "@typescript-eslint/parser": "^5.59.11", 42 | "eslint": "^8.42.0", 43 | "eslint-config-prettier": "^8.8.0", 44 | "eslint-plugin-prettier": "^4.2.1", 45 | "jest": "^29.5.0", 46 | "prettier": "^2.8.8", 47 | "source-map-support": "^0.5.21", 48 | "supertest": "^6.3.3", 49 | "ts-jest": "^29.1.0", 50 | "ts-loader": "^9.4.3", 51 | "ts-node": "^10.9.1", 52 | "tsconfig-paths": "^4.2.0", 53 | "typescript": "^5.1.3" 54 | }, 55 | "jest": { 56 | "moduleFileExtensions": [ 57 | "js", 58 | "json", 59 | "ts" 60 | ], 61 | "rootDir": "src", 62 | "testRegex": ".*\\.spec\\.ts$", 63 | "transform": { 64 | "^.+\\.(t|j)s$": "ts-jest" 65 | }, 66 | "collectCoverageFrom": [ 67 | "**/*.(t|j)s" 68 | ], 69 | "coverageDirectory": "../coverage", 70 | "testEnvironment": "node" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { CONFIG_DATABASE } from './commons/infrastructure/config-database'; 3 | import { ProductsModule } from './products/products.module'; 4 | 5 | @Module({ 6 | imports: [CONFIG_DATABASE(), ProductsModule] 7 | }) 8 | export class AppModule {} 9 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/commons/domain/dto/product-repository.dto.ts: -------------------------------------------------------------------------------- 1 | export interface IProductRepositoryDto { 2 | description: string; 3 | price: number; 4 | } 5 | 6 | export interface IGetProductRepositoryDto extends IProductRepositoryDto { 7 | productId: number; 8 | } 9 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/commons/domain/entities/entity-index.ts: -------------------------------------------------------------------------------- 1 | export * from './product.entity'; 2 | export * from './user.entity'; 3 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/commons/domain/entities/product.entity.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; 2 | 3 | @Entity({ name: 'product' }) 4 | export class ProductEntity { 5 | @PrimaryGeneratedColumn('increment') 6 | productId: number; 7 | 8 | @Column() 9 | description: string; 10 | 11 | @Column() 12 | price: number; 13 | } 14 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/commons/domain/entities/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; 2 | 3 | @Entity({ name: 'user' }) 4 | export class UserEntity { 5 | @PrimaryGeneratedColumn('increment') 6 | userId: number; 7 | 8 | @Column() 9 | name: string; 10 | 11 | @Column() 12 | lastName: string; 13 | } 14 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/commons/domain/repository/orm-product.repositor.interface.ts: -------------------------------------------------------------------------------- 1 | import { IGetProductRepositoryDto, IProductRepositoryDto } from '../dto/product-repository.dto'; 2 | 3 | export interface IOrmProductRepository { 4 | getAllProducts(): Promise; 5 | saveProduct(newProduct: IProductRepositoryDto): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/commons/domain/repository/orm-product.repository.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { DataSource, Repository } from 'typeorm'; 3 | import { IGetProductRepositoryDto, IProductRepositoryDto } from '../dto/product-repository.dto'; 4 | import { ProductEntity } from '../entities/product.entity'; 5 | import { IOrmProductRepository } from './orm-product.repositor.interface'; 6 | @Injectable() 7 | export class OrmProductRepository extends Repository implements IOrmProductRepository { 8 | constructor(dataSource: DataSource) { 9 | super(ProductEntity, dataSource.createEntityManager()); 10 | } 11 | 12 | async saveProduct(newProduct: IProductRepositoryDto): Promise { 13 | await this.save(newProduct); 14 | } 15 | 16 | async getAllProducts(): Promise { 17 | //TODO 18 | return await this.find(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/commons/infrastructure/config-database.ts: -------------------------------------------------------------------------------- 1 | import { TypeOrmModule } from '@nestjs/typeorm'; 2 | export const CONFIG_DATABASE = () => 3 | TypeOrmModule.forRoot({ 4 | type: 'mysql', 5 | host: 'localhost', 6 | port: 3306, 7 | username: 'root', 8 | password: 'root', 9 | database: 'ecommerce', 10 | autoLoadEntities: true 11 | }); 12 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/main.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { AppModule } from './app.module'; 3 | 4 | async function bootstrap() { 5 | const app = await NestFactory.create(AppModule, { cors: true }); 6 | await app.listen(3000); 7 | } 8 | bootstrap(); 9 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/products/application/produc-use-case.interface.ts: -------------------------------------------------------------------------------- 1 | import { ProductDto } from '../infrastructure/dto/product.dto'; 2 | 3 | export interface IUseCaseProductService { 4 | getAllProducts(): Promise; 5 | saveProducts(newProduct: ProductDto): Promise; 6 | } 7 | 8 | export interface IResponse { 9 | message: string; 10 | code: number; 11 | } 12 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/products/application/product-use-case.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable } from '@nestjs/common'; 2 | import { ICrudProductRepository } from '../domain/repository/product.interface'; 3 | import { ProductRepository } from '../domain/repository/product.repository'; 4 | import { ProductDto } from '../infrastructure/dto/product.dto'; 5 | import { IResponse, IUseCaseProductService } from './produc-use-case.interface'; 6 | 7 | @Injectable() 8 | export class ProductUseCaseService implements IUseCaseProductService { 9 | constructor(@Inject(ProductRepository) private readonly productRepository: ICrudProductRepository) {} 10 | 11 | async getAllProducts(): Promise { 12 | const products = await this.productRepository.getAllProducts(); 13 | return products.map((product) => product); 14 | } 15 | 16 | async saveProducts(newProduct: ProductDto): Promise { 17 | await this.productRepository.saveProducts(newProduct); 18 | return { message: 'Success', code: 200 }; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/products/domain/models/product-repository.model.ts: -------------------------------------------------------------------------------- 1 | export interface IProductRepositoryModel { 2 | productId: number; 3 | description: string; 4 | price: number; 5 | } 6 | 7 | export type ISaveProductRepositoryModel = Omit; 8 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/products/domain/repository/product.interface.ts: -------------------------------------------------------------------------------- 1 | import { IProductRepositoryModel, ISaveProductRepositoryModel } from '../models/product-repository.model'; 2 | 3 | export interface ICrudProductRepository { 4 | getAllProducts(): Promise; 5 | saveProducts(newProduct: ISaveProductRepositoryModel): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/products/domain/repository/product.repository.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable } from '@nestjs/common'; 2 | import { IOrmProductRepository } from '../../../commons/domain/repository/orm-product.repositor.interface'; 3 | import { OrmProductRepository } from '../../../commons/domain/repository/orm-product.repository'; 4 | import { IProductRepositoryModel, ISaveProductRepositoryModel } from '../models/product-repository.model'; 5 | import { ICrudProductRepository } from './product.interface'; 6 | @Injectable() 7 | export class ProductRepository implements ICrudProductRepository { 8 | constructor( 9 | @Inject(OrmProductRepository) 10 | private readonly ormProductRepository: IOrmProductRepository 11 | ) {} 12 | 13 | async getAllProducts(): Promise { 14 | const allProducts = await this.ormProductRepository.getAllProducts(); 15 | return allProducts.map((product) => ({ 16 | productId: product.productId, 17 | description: product.description, 18 | price: product.price 19 | })); 20 | } 21 | 22 | async saveProducts(newProduct: ISaveProductRepositoryModel): Promise { 23 | await this.ormProductRepository.saveProduct(newProduct); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/products/infrastructure/dto/product.dto.ts: -------------------------------------------------------------------------------- 1 | export class ProductDto { 2 | description: string; 3 | price: number; 4 | } 5 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/products/infrastructure/product.controller.ts: -------------------------------------------------------------------------------- 1 | import { Body, Controller, Get, Inject, Post } from '@nestjs/common'; 2 | import { IResponse, IUseCaseProductService } from '../application/produc-use-case.interface'; 3 | import { ProductUseCaseService } from '../application/product-use-case.service'; 4 | import { ProductDto } from './dto/product.dto'; 5 | 6 | @Controller('product') 7 | export class ProductController { 8 | constructor(@Inject(ProductUseCaseService) private readonly _productService: IUseCaseProductService) {} 9 | 10 | @Get() 11 | getProducts(): Promise { 12 | return this._productService.getAllProducts(); 13 | } 14 | 15 | @Post() 16 | saveProduct(@Body() product: ProductDto): Promise { 17 | return this._productService.saveProducts(product); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/src/products/products.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | import { ProductEntity } from '../commons/domain/entities/product.entity'; 4 | import { OrmProductRepository } from '../commons/domain/repository/orm-product.repository'; 5 | import { ProductUseCaseService } from './application/product-use-case.service'; 6 | import { ProductRepository } from './domain/repository/product.repository'; 7 | import { ProductController } from './infrastructure/product.controller'; 8 | 9 | @Module({ 10 | controllers: [ProductController], 11 | providers: [ProductUseCaseService, ProductRepository, OrmProductRepository], 12 | imports: [TypeOrmModule.forFeature([ProductEntity])] 13 | }) 14 | export class ProductsModule {} 15 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /demo-hexagonal-architecture/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "ES2021", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ARQUITECTURA HEXAGONAL 2 | 3 | ## ¡Hola, Coders! 4 | 5 | Si crees que mis videos te ayudan a mejorar profesionalmente o aprender algo nuevo, apoyame con tu suscripción.🤗 6 | 7 | # Mis Redes 8 | 9 | **Suscríbete a mi canal** 😎 10 | 11 | **YouTube:** [LogiDev](https://www.youtube.com/@LogiDev) 12 | 13 | **Twitch:** [Jimy Dolores](https://www.twitch.tv/jimydolores) 14 | 15 | **Sígueme en mis redes:** 16 | 17 | 👉Facebook : [LogiDev](https://facebook.com/LogiDev25) 18 | 19 | búscame como: [@LogiDev25](https://facebook.com/LogiDev25) 20 | 21 | 👉Instagram: [@jimydolores](https://instagram.com/jimydolores/) 22 | 23 | 👉Twitter: [Jimy Dolores](https://twitter.com/jimydolores) 24 | 25 | 👉LinkedIn:[Jimy Dolores](https://linkedin.com/in/jimyhuachodolores/) 26 | --------------------------------------------------------------------------------