├── 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 |
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 |
--------------------------------------------------------------------------------