{"id":15091653,"url":"https://github.com/amneweb/proyectofinalbackend","last_synced_at":"2026-01-05T00:13:28.912Z","repository":{"id":220945996,"uuid":"753004543","full_name":"Amneweb/ProyectoFinalBackend","owner":"Amneweb","description":"Repositorio con app del proyecto final del curso de Backend de la carrera Full Stack Developer de Coderhouse","archived":false,"fork":false,"pushed_at":"2024-07-27T02:04:02.000Z","size":7786,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-27T11:16:11.353Z","etag":null,"topics":["authentication","backend","express","handlebars","jwt","mocha-chai","swagger"],"latest_commit_sha":null,"homepage":"https://proyectofinalbackend-production-efdb.up.railway.app/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Amneweb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-05T09:30:27.000Z","updated_at":"2024-07-27T02:04:05.000Z","dependencies_parsed_at":"2024-03-02T15:23:29.093Z","dependency_job_id":"e166e32c-88d7-4880-ab10-3762ccdbc4ff","html_url":"https://github.com/Amneweb/ProyectoFinalBackend","commit_stats":{"total_commits":233,"total_committers":1,"mean_commits":233.0,"dds":0.0,"last_synced_commit":"b67780db072665750fb9fbe09f3ef1bb2bb23685"},"previous_names":["amneweb/proyectofinalbackend"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amneweb%2FProyectoFinalBackend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amneweb%2FProyectoFinalBackend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amneweb%2FProyectoFinalBackend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Amneweb%2FProyectoFinalBackend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Amneweb","download_url":"https://codeload.github.com/Amneweb/ProyectoFinalBackend/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244952231,"owners_count":20537463,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","backend","express","handlebars","jwt","mocha-chai","swagger"],"created_at":"2024-09-25T10:42:26.136Z","updated_at":"2026-01-05T00:13:28.885Z","avatar_url":"https://github.com/Amneweb.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ProyectoFinalBackend\n\nEl proyecto trata de un ecommerce de venta de baterías para vehículos y se puede visitar siguiendo el enlace en la sección \"About\" de este repositorio.\n\n**Si bien la página de inicio del sitio contiene una breve descripción con las características más importantes del proyecto, quiero aclarar en esta introducción que, aunque no se pedía en las consignas, la compra se puede iniciar sin que el usuario esté logueado. Es decir, cualquier usuario puede armar su carrito (que se guarda en el localstorage) y recién cuando confirma la compra el sistema le pide el registro/login.**\n\n## Paso a paso del curso y del proyecto\n\nEl curso de BackEnd de Coderhouse está estructurado en tres módulos, cada uno con diferentes objetivos, pero todos unidos por un hilo conductor que es el proyecto de una api completa para un ecommerce. Para poder avanzar en el curso es necesario ir realizando entregas con las mejoras aprendidas a medida que se desarrollan las clases.\n\n## DESAFIOS QUE FUERON COMPLETANDOSE HASTA LLEGAR AL PF\n\nEste readme contiene toda la información de las entregas principales y los desafíos intermedios, con las consignas de cada uno y en algunos casos, con aclaraciones sobre la solución propuesta por mí. Los desafíos están ordenados cronológicamente de más recientes a más antiguos.\n\n\u003e Los párrafos con borde gris a la izquierda representan las consignas de cada desafío\n\n### DESAFIO 14: **DOCUMENTACION DEL USUARIO, PERMISOS Y DATOS DE CONEXIÓN**\n\n\u003e configurar el servidor para que los usuarios puedan cargar documentación y según el tipo y objetivo de los archivos, éstos se carguen en diferentes carpetas. Para eso, modificar el modelo de User para que cuente con una nueva propiedad “documents” el cual será un array que contenga los objetos con propiedades nombre y link. Además, agregar una propiedad al usuario llamada “last_connection”, la cual deberá modificarse cada vez que el usuario realice un proceso de login y logout\n\n**DOCUMENTACION**\n\nPara la parte del redireccionamiento de los archivos agregué un middleware en las rutas de creación y modificación de productos, y en la nueva ruta de carga de documentación. Dicho middleware arma la ruta de destino del archivo en base a las propiedades baseUrl y path que vienen con el req.\n\nAunque no se pide, para la documentación hice una colección \"Documentation\", que contiene objetos con las propiedades código, obligatoriedad y nombre del archivo requerido. De esa manera, si en el futuro se requiere incluir otro documento como obligatorio, se puede subir su nombre y código a esa colección. Para verificar que un usuario puede tener permisos de premium, se comparan los códigos de los documentos que subió el usuario con los códigos de la documentación requerida, guardados en la colección \"documentation\".\n\nEl usuario carga los documentos desde la ruta /api/users/:uid/documents\n\n**CAMBIO DE ROL**\n\nEl usuario puede pedir el cambio de rol en cualquier momento, pero esto sólo ocurre cuando tiene cargados los 3 archivos solicitados\n\nLa ruta para el cambio de rol es /api/users/premium/:uid/\n\n**DATOS DE CONEXIÓN**\n\nEl timestamp se genera al momento de hacer login o logout y se guarda en la propiedad userConnection. En el caso del login, se le asigna el valor de Date.now() + 600000 que es el valor de maxAge que dura la cookie de login. Si el usuario nunca se desloguea, ese valor será el equivalente al deslogueo. Si se desloguea antes, el valor es reemplazado por el de desloguear.\n\n**VER USUARIOS INACTIVOS**\n\nEl administrador puede ver todos los usuarios que no se han conectado en un determinado lapso de tiempo en la ruta:\n\nhttp://localhost:8080/api/users/sinactividad/?meses=3\n\nEn un ecommerce real, si el valor ingresado en el parámetro meses es 3, el lapso será un tiempo real de 90 días, sin embargo, a los efectos de probar su funcionamiento, el código está realizado de manera que cada \"mes\" equivale a poco más de 8 minutos. (El detalle del cálculo está en la descripción de la ruta de postman)\n\n---\n\n### DESAFIO 13: **TESTING**\n\n\u003e Realizar módulos de testing para tu proyecto principal, utilizando los módulos de mocha + chai + supertest\n\n**Trabajo realizado**\n\n\u003e [!TIP]\n\u003e COMANDOS PARA REALIZAR EL TEST\n\nPara realizar los tests se tendrán abiertas dos terminales, una para el servidor y otra para el test. Los comandos para inicializar el test en cada una de ellas son:\n\n**SERVIDOR**\n\n```\nnode --watch src/app.js --test test\n```\n\n**TEST**\n\n```\nnpm test\n```\n\n**TESTS QUE SE REALIZAN**\n\nSe realizarán tests unitarios (TDD) y tests de integración (BDD) de toda la app en cada una de las rutas principales.\n\n---\n\n### DESAFIO 12: **DOCUMENTAR LA API**\n\n\u003e Realizar la configuración necesaria para tener documentado tu proyecto final a partir de Swagger.\n\nSe documentó parte de la API con Swagger.\nLa ruta para ver la documentación es **http://localhost:8080/api/docs/**\n\n---\n\n### DESAFIO 11: **RECUPERO DE CONTRASEÑA Y ROL PREMIUM**\n\n\u003e Realizar un sistema de recuperación de contraseña, la cual envíe por medio de un correo un botón que redireccione a una página para restablecer la contraseña (no recuperarla). Establecer un nuevo rol para el schema del usuario llamado “premium” el cual estará habilitado también para crear productos Modificar el schema de producto para contar con un campo “owner”, el cual haga referencia a la persona que creó el producto\n\nPara este desafío implementé un método de recuperación de contraseña en 3 pasos\n\n- El cliente visita la página de recuperación de contraseña, carga su dirección de correo y el sistema le envía un correo con un link\n- El cliente hace click en el link y es dirigido a una página en donde ingresa un nuevo password\n- Si el password es distinto al anterior, se guarda en el sistema, si no, es rechazado\n\n**Controles en cada uno de los pasos**\n\n- Cuando el cliente carga su dirección de correo, primero se verifica que corresponda a un cliente registrado\n- En el momento en que se envía el formulario que da la orden del envío del correo, se genera una cookie con una vida de 1 hora (en el ejemplo la hice de 10 minutos)\n- En la cookie se guarda un jwt token que tiene el email del usuario\n- Ese token se agrega como parámetro en la ruta del enlace que recibe el usuario por correo\n- Cuando el usuario hace click en el enlace, en el endpoint se verifica que la cookie todavía exista y que el token guardado en la cookie sea el mismo que el que llega por parámetro.\n- Si son iguales, el correo guardado en el token es el que se renderiza en el último paso, cuando se le pide al usuario que ingrese un nuevo password\n- Antes de guardar el password en la BDD, se verifica que no sea igual al anterior\n\n---\n\n### DESAFIO 10: **IMPLEMENTACION DE LOGGER**\n\n\u003e Basado en nuestro proyecto principal, implementar un logger. Primero, definir un sistema de niveles que tenga la siguiente prioridad (de menor a mayor): **debug, http, info, warning, error, fatal** Después implementar un logger para desarrollo y un logger para producción.\n\n**_WINSTON_**\n\n**RUTA DE PRUEBA**\n\nEl endpoint /loggertest muestra sólo el log que se genera en app.js a través del middleware addLogger. Haciendo correr las otras requests se van generando diferentes logs con mensajes, warnings y errores.\n\n**LOGGERS PARTICULARES**\n\nPara cada endpoint, el middleware genera un log con la ruta correspondiente. Los demás logs son generados por otros loggers que se llaman desde los distintos procesos (hasta el momento tengo creados los loggers que se llaman desde el controlador de usuarios, desde productos y desde custom router) Todos los loggers se crean en el archivo **logger.config.js**\n\n**ARCHIVO GENERADO**\n\nSegún el modo en que estemos, se genera un archivo global.log (modo producción) o globalDEV.log (modo desarrollo)\n\n---\n\n### DESAFIO 9: **MOCKING Y MANEJO DE ERRORES**\n\n\u003e Se aplicará un módulo de mocking y un manejador de errores a tu servidor actual\n\n---\n\n### TERCERA PRE-ENTREGA: MEJORA DE LA ARQUITECTURA DEL SERVIDOR\n\n\u003e Profesionalizar el servidor. Aplicar una arquitectura profesional para nuestro servidor. Aplicar prácticas como patrones de diseño, mailing, variables de entorno. etc. Modificar la capa de persistencia para aplicar los conceptos de Factory (opcional), DAO y DTO.\n\n**COMENTARIOS SOBRE LA TERCER ENTREGA Y DESAFIOS POSTERIORES**\n\nEn este caso preferí dejar de lado el front-end y todo el proceso de registro, compra, armado de carrito, etc, se deberá realizar desde postman, para lo cual generé un archivo con la colección de requests.\n\n**_Tercer entrega actualizada (incluye mocking, factory y winston)_**\n\n**Comandos para persistencia:**\n\n- FS: node --watch src/app.js --persist fs\n- MONGO: node --watch src/app.js --persist mongodb\n\nEn el caso de mongo se puede escribir \"npm run dev\" y automáticamente usa el servicio de mongo\n\n**Requests en Postman**\n\nLas requests están organizadas en carpetas: Usuarios, Carritos y Productos. Hay además dos requests fuera de las carpetas, una para probar el envío de emails desde un endpoint, y otra para ver los productos generados con faker-js\n\n**Proceso de compra**\n\nPasos a seguir para armar un carrito y hacer la compra (cada paso corresponde a una request)\n\n\u003e [!IMPORTANT]\n\u003e Este proceso completo sólo funciona con la persistencia de Mongo\n\n1. Registrar un nuevo usuario con rol \"user\"\n1. Loguear el usuario\n1. Crear carrito vacío\n1. Ver carrito de usuario logueado y copiar el id que aparece como respuesta de la query\n1. Agregar productos al carrito teniendo en cuenta que hay que pegar el id del carrito en la ruta del endpoint correspondiente (Si se agregan productos con poco stock se puede evaluar el funcionamiento del carrito remanente)\n1. Comprar el carrito (pegar el id del carrito en la ruta)\n1. Se puede ver el carrito remanente (si se compraron productos con poco stock) volviendo a ejecutar la request para ver el carrito del usuario logueado\n\n**Sobre Factory**\n\nUso factory sólo para cambiar el método de persistencia de carritos y productos. NO lo uso para cambiar entre desarrollo y producción.\nPor otro lado, tampoco armé un servicio de usuarios con fileSystem, por lo que para agregar productos necesito la conexión con Mongo, así que en \"fs\" también inicializo Mongo (archivo **factory.js** línea 38)\n\n- En FileSystem se pueden agregar productos, borrar y modificar. Se pueden crear carritos a los que se les puede agregar productos.\n- El carrito se puede generar y se le pueden agregar productos sólo desde el rol de usuario.\n- Se pueden ver los carritos existentes sólo desde el rol de admin\n\n**Navegación en el front-end**\n\n\u003e [!CAUTION]\n\u003e El desarrollo del front end quedó en stand by. Algunas funcionalidades tienen fallas. Por ahora las pruebas deben hacerse todas desde postman\n\nHay 4 vistas principales:\n\n- **Catálogo** que sería para el público en general\n- **Lista de productos** para el administrador\n- **Lista de carritos** para el administrador\n- **Custommer support** con el chat de usuarios\n\nY otras dos vistas secundarias:\n\n- **Carrito del usuario**\n- **Detalle del producto**\n\n**CARRITO**\n\nCarga de productos al carrito: se puede hacer desde el catálogo. Si no hay ningún carrito generado, cuando el usuario hace click en el botón \"comprar\" de un producto, primero se arma un carrito vacío y luego se agrega el producto.\nUna vez que se genera un carrito, el ID se guarda en el local storage y a partir de ahí todos los productos que se compran se agregan al carrito guardado en storage. Para acceder al carrito, se puede usar el link en la parte superior derecha de la página.\nCuando se borra el carrito, se elimina del storage.\n\n**PRODUCTOS**\n\nSe pueden agregar productos desde el formulario al final del listado de productos del administrador. Para modificarlos, se hace click en el nombre del producto y se abre una ventana modal.\nLa carga de un producto se hace enviando el formulario html con el método post del mismo formulario. (lo hice así porque no pude enviar el formulario con datos y archivos -multipart form- usando fetch) Para volver a la vista de front end desde el endpoint hice una redirección. No creo que sea la forma más elegante de resolverlo, pero es lo único que pude hacer funcionar.\nLa modificación de los productos se hace con fetch. Se pueden modificar los datos por un lado, o subir las imágenes. Se hacen por separado.\n\n**PAGINACION, ORDENAMIENTO, ETC**\n\nPor ahora sólo programé la paginación, con una cantidad de productos por página fija y se ordena por cantidad de stock.\nTengo que pensar un poco más cómo hacer que la cantidad de productos pueda ser elegida por el usuario, porque con la paginación, al ir a la segunda página el límite que se cargaba como req.query la primera vez, ya no queda en la url. (tengo que ver si lo puedo agregar desde handlebars con un if, pero todavía no lo pude pensar bien)\n\n**CARPETAS**\n\n\u003e [!WARNING]\n\u003e El árbol está desactualizado. Es tarea pendiente.\n\n```\n📂 ROOT\n|__ 📂 PUBLIC\n|        |__ 📂 IMG\n|        |__ index.html (está vacío)\n|__ 📂 SRC\n|        |__ 📂 FILES\n|        |       |__ carritos.json\n|        |       |__ productos.json\n|        |__ 📂 ROUTES\n|        |       |__ cart.routes.js\n|        |       |__ products.routes.js\n|        |__ 📂 SCRIPTS\n|        |       |__ CartManager.js\n|        |       |__ ProductManager.js\n|        |__ app.js\n|__ utils.js\n|__ packages, README, .gitignore, etc\n```\n\n---\n\n### DESAFIO 8: **REESTRUCTURA DEL SERVIDOR**\n\n\u003e El proyecto debe contar con capas de routing, controlador, dao, con nuestras vistas bien separadas y con las responsabilidades correctamente delegadas.\n\n---\n\n### DESAFIO 7: **REFACTOR DEL LOGIN CON BYCRYPT Y JWT**\n\n\u003e Se deberá contar con un hasheo de contraseña utilizando bcrypt Se deberá contar con una implementación de passport, tanto para register como para login. Implementar el método de autenticación de Github a la vista de login.\n\n---\n\n### DESAFIO 6: **IMPLEMENTACION DE LOGIN**\n\n\u003e Ajustar nuestro servidor principal para trabajar con un sistema de login. Deberá contar con todas las vistas de register, login y profile, así también como las rutas de router para procesar el registro y el login. Una vez logueado, el usuario es dirigido a la vista de productos.\n\n---\n\n### SEGUNDA PRE-ENTREGA: PROFESIONALIZANDO LA BDD\n\n\u003e Contarás con Mongo como sistema de persistencia principal. Tendrás definidos todos los endpoints para poder trabajar con productos y carritos. OBJETIVOS: Profesionalizar las consultas de productos con filtros, paginación y ordenamientos Profesionalizar la gestión de carrito para implementar los últimos conceptos vistos.\n\n---\n\n### DESAFIO 5: **MONGO Y MONGOOSE**\n\n\u003e Agregar el modelo de persistencia de Mongo y mongoose a tu proyecto. Crear una base de datos llamada “ecommerce” dentro de tu Atlas, crear sus colecciones “carts”, “messages”, “products” y sus respectivos schemas.\n\n---\n\n### DESAFIO 4: **WEBSOCKETS Y HANDLEBARS**\n\n\u003e Configurar el servidor para integrar el motor de plantillas Handlebars e instalar un servidor de socket.io al mismo. Crear una vista “index.handlebars” la cual contenga una lista de todos los productos agregados hasta el momento.\n\n---\n\n### PRIMERA PRE-ENTREGA: ROUTER Y MULTER\n\n\u003e Desarrollar el servidor basado en Node.JS y express, que escuche en el puerto 8080 y disponga de dos grupos de rutas: /products y /carts. Dichos endpoints estarán implementados con el router de express\n\n---\n\n### DESAFIO 3: **SERVIDOR CON EXPRESS**\n\n\u003e Desarrollar un servidor basado en express donde podamos hacer consultas a nuestro archivo de productos. Desarrollar un servidor express que, en su archivo app.js importe al archivo de ProductManager que actualmente tenemos.\n\n---\n\n### DESAFIO 2: **MANEJO DE ARCHIVOS**\n\n\u003e Realizar una clase de nombre “ProductManager”, el cual permitirá trabajar con múltiples productos. Éste debe poder agregar, consultar, modificar y eliminar un producto y manejarlo en persistencia de archivos (basado en entregable 1).\n\n---\n\n### DESAFIO 1: **CLASES CON ECMA SCRIPT**\n\n\u003e Realizar una clase “ProductManager” que gestione un conjunto de productos. Cada producto que gestione debe contar con las propiedades title, stock, description, thumb, etc\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famneweb%2Fproyectofinalbackend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famneweb%2Fproyectofinalbackend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famneweb%2Fproyectofinalbackend/lists"}