Erick Villatoro
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Proyecto Fase 1 ## Datos de integrantes | Coordinador | Carnet | Nombre | Porcentaje de trabajo | |:-----------:|:---------:|:------------------------------------:|:------:| |x| 201800496 | Juan Antonio Solares Samayoa | 25% | | | 201900907 | Erick José André Villatoro Revolorio | 25% | | | 201807335 | Juan Diego Alvarado Salguero | 25% | | | 201602719 | Christofer William Borrayo López | 25% | ## Índice # Comunicación de los servicios <table> <thead> <tr> <th>Id: 1</th> <th>Nombre: Recepción de Productos</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> alta</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Es importante como tienda realizar el aumento de inventario o la agregación de productos nuevos con su cantidad de inventario inicial al inventario, al comprar productos a una tienda externa a través de un usuario empresarial dentro de su página web.</td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Inventario</td> </tr> <tr> <td colspan="2"><b>Criterios de Aceptación:</b><br>Una vez realizada la entrega de productos por ruta, se actualizará el inventario de la tienda agregando la cantidad de productos enviados en la commanda. <br><br><b>Ruta:</b> /inventario/recepcion<br><b>Método:</b> PUT<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> <tr> <td>Authorization</td> <td>header</td> <td>Bearer&lt;token&gt;</td> </tr> </tbody> </table> <br> <b>Body:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>productos</td> <td>Array</td> <td>Arreglo de Objetos JSON con información de los productos </td> </tr> </tbody> </table> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>SKU</td> <td>int</td> <td>identificador único del producto seleccionado.</td> </tr> <tr> <td>cantidad</td> <td>int</td> <td>Cantidad deseada del producto seleccionado.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 200 <br> <b>Salida:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>status</td> <td>int</td> <td>El código 200 de respuesta exitosa.</td> </tr> <tr> <td>msg</td> <td>string</td> <td>Indicación de éxito sobre la operación.</td> </tr> </tbody> </table> <br> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>400</td> <td>Datos con formato invalido dentro de la petición.</td> </tr> <tr> <td>401</td> <td>Credenciales incorrectas dentro del token.</td> </tr> <tr> <td>404</td> <td>indica que el servidor no pudo encontrar el recurso solicitado</td> </tr> </tbody> </table> <b>Body salida:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>status</td> <td>int</td> <td>El código de respuesta fallida. </td> </tr> <tr> <td>msg</td> <td>string</td> <td>Mensaje con información del error.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre> { "productos": [ { "sku": 3, "cantidad": 10 }, { "sku": 5, "cantidad": 2 } ] } </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { "status": 200, "msg" : "Stock del producto actualizado" } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { "status": 400, "msg": "Formato invalido" } </pre> <pre> { "status": 401, "msg": "Token no válido" } </pre> <pre> { "status": 404, "msg": "No se encontró el recurso solicitado" } </pre> <b>Ejemplos de parámetros de token</b> <pre> { "id_grupo": "identificador de la tienda que nos vendió los productos", "seccion": "Seccion de la tienda de la tienda que nos vendió los productos" } </pre> </td> </tr> </tbody> </table> <table> <thead> <tr> <th>Id: 02</th> <th>Nombre: Registro de compra externa</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> alta</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Es necesario poder registrar la transacción de compra realizada por un sistema externo (previo a esto la compra debió ser autorizada por el administrador). </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Compra</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> Luego de que el administrador autorice la compra externa, el sistema registrará la transacción realizada. <br><br> <b>Ruta:</b> /compra/registro-externo<br> <b>Método:</b> POST<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> <tr> <td>Authorization</td> <td>header</td> <td>Bearer&lt;token&gt;</td> </tr> </tbody> </table> <br> <b>Body:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Fecha</td> <td>Date</td> <td>Fecha cuando se autorizó la venta, con el siguiente formato: “YYYY-MM-DD”.</td> </tr> <tr> <td>productos</td> <td>Array</td> <td>Arreglo de Objetos JSON con información de los productos.</td> </tr> <tr> <td>SKU</td> <td>int</td> <td>identificador único del producto seleccionado. </td> </tr> <tr> <td>cantidad</td> <td>int</td> <td>Cantidad deseada del producto seleccionado.</td> </tr> <tr> <td>precio_unitario</td> <td>decimal</td> <td>Precio unitario al cual se compró el producto.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 201 <br> <b>Salida:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>status</td> <td>INT</td> <td>código de respuesta exitosa</td> </tr> <tr> <td>msg</td> <td>STRING</td> <td>mensaje describiendo la operación realizada.</td> </tr> </tbody> </table> <br> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>400</td> <td>Datos con formato invalido dentro de la petición.</td> </tr> <tr> <td>401</td> <td>Credenciales incorrectas dentro del token.</td> </tr> </tbody> </table> <b>Body salida:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>status</td> <td>int</td> <td>El código de respuesta fallida. </td> </tr> <tr> <td>msg</td> <td>string</td> <td>Mensaje con información del error.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre> { Fecha:”2023-02-12”, productos: [ { sku: 3, cantidad: 10, precio_unitario:10 }, { sku: 5 cantidad: 2, precio_unitario:10 }, ] } </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { “status”: 201, “msg”: Transacción realizada con éxito } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 400, “msg”: “Formato invalido” } </pre> <pre> { “status”: 401, “msg”: “Token no válido” } </pre> <b>Ejemplos de parámetros de token</b> <pre> { "id_grupo": "identificador de la tienda que nos vendió los productos", "seccion": "Seccion de la tienda de la tienda que nos vendió los productos" } </pre> </td> </tr> </tbody> </table> # Diagrama de actividades ## Servicio de Compras ![](https://i.imgur.com/OytHJld.png) ## Servicio de Inventario ![](https://i.imgur.com/qwHYtYq.png) ## Servicio de Ventas ![](https://i.imgur.com/ySqJSTD.png) # Descripción de la seguridad de la aplicación La seguridad de la aplicación para este software de gestión de actividades empresariales es fundamental para garantizar la protección de los datos de la empresa y sus clientes, así como para mantener la continuidad del negocio. Hay varios aspectos de seguridad que deben ser considerados para garantizar la protección como los siguientes: 1. **Autenticación y autorización:** Como la aplicación permitirá el registro de usuarios, es fundamental que exista un sistema de autenticación seguro para garantizar que sólo los usuarios autorizados puedan acceder a la aplicación. Esto se puede lograr mediante la implementación de autenticación de dos factores, contraseñas seguras y tokens de acceso. Además, la aplicación debe contar con un sistema de autorización para garantizar que los usuarios tengan acceso sólo a los recursos y datos que les corresponden. En este caso se utilizará una encriptación de contraseñas utilizando SHA256 en conjunto con un sistema de autenticación que haga uso de tokens generados desde el servidor siguiendo los siguientes pasos: 1. Implementar un endpoint en Flask para que el usuario pueda ingresar sus credenciales (usuario y contraseña) y enviarlos al servidor. 2. Verificar las credenciales del usuario en el servidor mediante una consulta a una base de datos o a un servicio externo, y si son correctas, generar un token de acceso para el usuario. 3. El token de acceso debe ser una cadena aleatoria única que se genere utilizando SHA256. Para esto se generará una cadena aleatoria y luego se aplicará SHA256 sobre ella. La cadena aleatoria se generará con la función `secrets.token_hex()` en Python. 4. El token de acceso debe ser enviado de vuelta al cliente para que lo utilice en las solicitudes futuras a la aplicación. Se puede enviar el token de acceso en la respuesta del servidor como un encabezado o en el cuerpo de la respuesta. 5. Para cada solicitud que haga el cliente, el token de acceso debe ser enviado al servidor en un encabezado personalizado (Authorization: Bearer \<token>). 6. En el servidor, se debe verificar si el token de acceso es válido y si está autorizado para acceder al recurso solicitado. Se puede almacenar el token en una base de datos o en memoria en el servidor para validar su autenticidad y autorización. 7. Si el token de acceso no es válido o no está autorizado para acceder al recurso solicitado, se debe responder con un código de error apropiado. 8. El servidor debe proporcionar una manera de revocar los tokens de acceso para que los usuarios puedan cerrar sesión o en caso de que el token haya sido comprometido. Para esto se puede implementar un endpoint para que los usuarios puedan enviar una solicitud para revocar su token. 9. El servidor también debe renovar periódicamente los tokens de acceso para garantizar la seguridad del sistema y evitar la exposición prolongada del mismo. Se puede establecer una duración de validez del token y renovarlos antes de que expiren. 2. **Protección de datos:** La aplicación debe contar con medidas de protección de datos para garantizar la confidencialidad e integridad de la información que maneja. Es importante que los datos se almacenen de forma encriptada en bases de datos seguras, y que los datos en tránsito se protejan mediante protocolos de cifrado SSL/TLS. Para esto se hará uso de lo visto anteriormente con los siguientes pasos: 1. Crear una base de datos que almacene los usuarios y sus contraseñas. Las contraseñas se almacenarán encriptadas mediante un algoritmo de hash seguro (SHA256). 2. Implementar un endpoint en Flask para que el usuario pueda ingresar sus credenciales (usuario y contraseña) y enviarlos al servidor. 3. En el servidor, se debe recuperar la contraseña encriptada del usuario de la base de datos. Luego, se debe aplicar el mismo algoritmo de hash (SHA256) a la contraseña ingresada por el usuario y compararla con la contraseña almacenada en la base de datos. 4. Si las contraseñas coinciden, el servidor debe generar un token de acceso para el usuario y enviarlo al cliente. En caso contrario, el servidor debe responder con un código de error apropiado. 5. Es importante asegurarse de que las contraseñas no se transmitan en texto plano en la red. Para ello, se hará uso de HTTPS para encriptar las comunicaciones entre el cliente y el servidor. 6. Se establecerá un límite de intentos de inicio de sesión (5 intentos) para evitar ataques de fuerza bruta. Para esto se implementará un contador de intentos de inicio de sesión fallidos y se bloqueará temporalmente la cuenta si se supera el número de intentos. 3. **Prevención de ataques:** La aplicación debe contar con medidas de protección para prevenir ataques de hackers, como ataques de fuerza bruta, inyección de SQL y Cross-Site Scripting. Para ello, se implementarán técnicas de validación de datos, filtrado y sanitización de inputs, y se aplicarán actualizaciones de seguridad regulares. Para ello se hará uso de lo siguiente: 1. Enviar el token de acceso con cada solicitud al servidor. Esto hará mediante el uso de un header HTTP personalizado (Authorization: Bearer \<token>). El token se generará según lo visto al inicio de esta sección. 2. En el servidor, se debe verificar la validez del token en cada solicitud. Esto realizará mediante el uso de un middleware en Flask que verifique la existencia y validez del token en el header HTTP. 3. Es importante asegurarse de que el token no se pueda falsificar o manipular. Para ello, se utilizará un algoritmo de firma digital, como HMAC (queda a discusión su implementación), para asegurarse de que el token es auténtico y no ha sido alterado. 4. Además de la autenticación, es necesario asegurarse de que los usuarios solo puedan acceder a los endpoints y recursos que están autorizados a utilizar. Esto se hará mediante el uso de roles y permisos. Para esto se definirán roles de usuario, como "administrador", "empleado" y "cliente", y se asignarán permisos específicos a cada rol. Luego, se verificará los permisos del usuario en cada solicitud al servidor. 5. Es importante proteger los endpoints sensibles con autenticación y autorización. Para esto se protegerán los endpoints de administración y gestión de recursos con permisos de "administrador" y los endpoints de consulta de información con permisos de "empleado" o "cliente". 4. **Auditoría y monitoreo:** La aplicación debe contar con un sistema de auditoría y monitoreo para detectar actividades sospechosas y evitar fraudes. Esto se puede lograr mediante la implementación de logs de actividad y la monitorización de los mismos. 1. Se deben definirán roles y permisos específicos para cada usuario en la aplicación como se vio en el inciso anterior. 2. Se pueden utilizar decoradores de funciones para proteger los endpoints sensibles con autenticación y autorización. Este decorador puede verificar los permisos del usuario antes de permitir el acceso al endpoint y puede ser aplicado a cualquier endpoint que requiera permisos específicos. 3. En el decorador de función personalizado, se puede verificar el rol y los permisos del usuario para determinar si se le debe permitir el acceso al endpoint. Esto se puede hacer utilizando la información del usuario almacenada en el token de acceso. 4. Para facilitar el monitoreo, este decorador puede ser implementado en el middleware para que pueda ser utilizado por todos los servicios si fuese necesario. 5. Se debe implementar un log de actividad en el middleware para llevar un control de las acciones solicitadas a los servidores y de esta manera poder generar estadísticas en un futuro acerca del uso de los servicios y generar acciones pertinentes para adelantarse a posibles eventos futuros. 6. Se puede implementar como un añadido, softwares de monitoreo en tiempo real como Prometheus, Grafana, Datadog, New Relic, Sentry, etc. 5. **Cumplimiento normativo:** Dado que la aplicación maneja datos personales de clientes y empleados, es importante que se cumplan con las regulaciones de protección de datos, como la RGPD en Europa o la Ley de Protección de Datos Personales en Latinoamérica. Se deben implementar medidas técnicas y organizativas adecuadas para garantizar el cumplimiento de estas regulaciones como: 1. Es importante conocer las normativas de seguridad de la información que se aplican en la región o país donde se utilizará la aplicación, ya que estas normativas pueden variar significativamente. Es necesario asegurarse de cumplir con todas las leyes y regulaciones relevantes, como la protección de datos personales, la seguridad cibernética, el comercio electrónico, etc. 2. La aplicación debe contar con medidas de seguridad adecuadas para proteger los datos personales y financieros de los usuarios (como se vió en los puntos anteriores). Es necesario implementar el cifrado de datos y contraseñas seguras, así como medidas de protección contra ataques de phishing y malware. 3. Contar con un sistema de autenticación y autorización robusto para garantizar que solo los usuarios autorizados puedan acceder a la aplicación y a la información almacenada en ella. Se debe limitar el acceso a la información según los roles y permisos de cada usuario, y se deben implementar medidas de control de acceso a la información crítica. 4. Realizar pruebas regulares de seguridad para identificar y corregir vulnerabilidades en la aplicación. Se deben realizar pruebas de penetración, análisis de vulnerabilidades y pruebas de seguridad de la aplicación para identificar los posibles riesgos de seguridad utilizando Burp Suite, OWASP, ZAP, Nmap, etc. 5. Contar con un plan de continuidad de negocio en caso de interrupciones o fallas del sistema. Es necesario contar con copias de seguridad de los datos y sistemas redundantes para garantizar que la aplicación pueda recuperarse rápidamente en caso de una falla. 6. Todos los usuarios que interactúen con la aplicación deben estar capacitados en las medidas de seguridad y cumplimiento normativo que se aplican a la aplicación. Es necesario capacitar al personal en temas como la gestión de contraseñas, la detección de ataques de phishing y la gestión de datos personales. 6. **Actualizaciones y parches de seguridad:** Es importante mantener la aplicación actualizada con las últimas versiones y parches de seguridad para garantizar la protección contra posibles vulnerabilidades y amenazas. 1. Mantener un registro de todas las actualizaciones y parches aplicados a la aplicación. Esto permitirá realizar un seguimiento de los cambios realizados y garantizar que se apliquen correctamente. 2. Implementar un proceso de pruebas completo antes de implementar cualquier actualización o parche de seguridad en la aplicación. Esto permitirá identificar posibles problemas y errores antes de que se produzcan en un ambiente de producción. 3. Realizar actualizaciones y parches de seguridad regularmente. Los sistemas operativos (si es que se llegase a utilizar alguno), las bibliotecas utilizadas y otros componentes se actualizan constantemente para corregir problemas de seguridad y errores. Es fundamental que se realicen las actualizaciones y parches necesarios para mantener la seguridad y estabilidad de la aplicación. 4. Planificar cuidadosamente los tiempos de inactividad necesarios para implementar actualizaciones y parches de seguridad. Esto minimizará las interrupciones en el servicio de la aplicación y garantizará una actualización y parche de seguridad exitosos. 5. En caso de que surjan problemas después de una actualización o parche de seguridad, es importante tener un proceso de reversión. Esto permitirá volver a un estado anterior de la aplicación antes de la actualización o parche. 6. Estar al día en cuanto a las tendencias y novedades en seguridad para asegurarse de que se está aplicando las mejores prácticas de seguridad. # Documentación de los pipelines Antes que nada se definirá las herramientas a utilizar de las diversas herramientas de control de versiones, se escogerá Git por su amplio uso y su compatibilidad con la mayoría de plataformas de hosting de repositorios, en este caso la plataforma Gitlab que nos permitirá un manejo y control más completo de CI/CD. Se utilizará diversas ramas para el control de versiones siguiendo el flujo de trabajo de control de versiones GitFlow para mantener una estructura organizada y predecible en el control de versiones. Con respecto a los pipelines, cada uno de estos se crearán en un entorno de prueba independiente con sus respectivos pasos. Estos dependiendo del servicio que se esté integrando, podrán ser ejecutados cosecutivamente junto otro pipeline que se considere necesario para probar e implementar la totalidad del servicio. Estos pipelines se integrarán con herramientas de gestión de incidentes como Jira para notificar al equipo y comenzar la resolución del incidente. Cabe recordar que no todos los pipelines serán aplicados al momento de implementar un servicio, estos serán decididos por el equipo más adelante y no todas las ramas creadas podrán utilizarlos, esta decisión quedará a elección del equipo. El comportamiento del pipeline de forma general será el siguiente: ![Pipeline - Comportamiento general](https://i.imgur.com/fyRyio2.png) ## Autenticación y autorización de usuarios Este pipeline tiene como objetivo garantizar que solo los usuarios autorizados tengan acceso a la aplicación y a las funciones específicas de la misma. Pasos: 1. **Verificación de identidad del usuario:** Se integra la solicitud de credenciales de usuario de inicio de sesión (nombre de usuario y contraseña) y se verifica la identidad del usuario utilizando el mecanismo de autenticación seguro implementado. 2. **Autorización de usuarios:** Se comprueba que el usuario tenga los permisos necesarios para acceder a las funciones específicas de la aplicación que está intentando utilizar. Se utiliza un sistema de roles y permisos para gestionar la autorización de los usuarios en cada servicio que se este implementando. **Requisitos para considerar al pipeline como completado** * Los usuarios con roles específicos pueden acceder al servicio. * Los usuarios con roles no especificados no pueden acceder al servicio. ![Pipeline - Autenticación y autorización de usuarios](https://i.imgur.com/TFsQXHO.png) ## Monitoreo y registro de actividades de usuario Este pipeline tiene como objetivo monitorear y registrar las actividades de usuario para detectar cualquier actividad sospechosa o maliciosa. 1. **Monitoreo de actividades de usuario:** Se monitorea y registra todas las actividades de usuario, incluyendo el inicio de sesión, la creación de cuentas y las transacciones de compra y venta ingresandola en un log. 2. **Detección de actividades maliciosas:** En base al monitoreo, se utilizan técnicas de detección de anomalías y aprendizaje automático para detectar patrones de actividad malintencionada y alertar al equipo de la aplicación en caso de que se detecte una actividad sospechosa. **Requisitos para considerar al pipeline como completado** * Se logra realizar un registro correcto de los pasos dentro del log. * Al detectar alguna acción anómala (como múltiples inicios de sesión fallidos) el equipo es informado de esto. ![Pipeline - Monitoreo y registro de actividades de usuario](https://i.imgur.com/qouuqAl.png) ## Gestión de parches y actualizaciones de seguridad Este pipeline tiene como objetivo garantizar que la aplicación esté actualizada con los últimos parches y actualizaciones de seguridad para protegerla contra vulnerabilidades conocidas. 1. **Identificación de vulnerabilidades:** Se procede a verificar las versiones más actualizadas de las librerías o softwares utilizados. **Requisitos para considerar al pipeline como completado** * Las versiones de librerías utilizadas están actualizadas. * *Si existe una versión de librería a actualizar que deja de ser compatible con alguna otra librería que se esté utilizando, el pipeline puede pasar como aprobado pero se informa al equipo sobre esto para poder tomar acciones al respecto.* ![Pipeline - Gestión de parches y actualizaciones de seguridad](https://i.imgur.com/nVVfwJm.png) ## Pruebas unitarias Este pipeline tiene como objetivo ejecutar directamente en el servicio pruebas para verificar su correcto funcionamiento. 1. **Coverage del código** Se cuenta con la implementación de un software de coverage (coverage.py) que permita verificar que se este cubriendo como mínimo un 75% del código en las pruebas unitarias a realizar. 2. **Pruebas de éxito** Se verifica que el servicio funcione correctamente en un caso simulado donde todas las entradas sean correctas. 2. **Pruebas de fracaso** Se verifica que el servicio responda correctamente ante casos simulados de error en el ingreso de datos desde el cliente o fallos internos del servidor. **Requisitos para considerar al pipeline como completado** * Se ha ejecutado como mínimo una prueba de éxito para cada microservicio. * Se ha ejecutado como mínimo una prueba de fracaso para cada microservicio. * Todas las pruebas han sido exitosas. * Se posee un coverage del código del 75%. ![Pipeline - Pruebas unitarias](https://i.imgur.com/j6ZFm36.png) ## Construcción Este pipeline tiene como objetivo la construcción de los servicios en una imagen de docker y su almacenamiento. 1. **Construcción de contenedor** El código implementado se construye como un contenedor de docker. 2. **Almacenamiento** El contenedor creado es subido a una plataforma de nube privada para su almacenamiento (GCR). **Requisitos para considerar al pipeline como completado** * Se ha completado la construcción del contenedor de docker de forma exitosa. * Se ha actualizado la imagen de docker del servicio en la plataforma privada. ![Pipeline - Construcción](https://i.imgur.com/tPc1avF.png) ## Deployment Este pipeline tiene como objetivo el despliegue de una imagen almacenada en una nube privada (GCR) en un orquestador de contenedores (GKE) previamente configurado. 1. **Despliegue en GKE** A partir de la configuración ya realizada en el orquestador de contenedores se procederá a crear o reemplazar la imagen del servicio. **Requisitos para considerar al pipeline como completado** * Se ha implementado la imagen actualizada al orquestador de contendores. ![Pipeline - Deployment](https://i.imgur.com/CumvwVd.png) # Análisis y solución de la problemática La problemática que se presenta en este caso es el desarrollo de una aplicación de Software para gestión de actividades empresariales que cumpla con ciertas funcionalidades específicas, tales como: * Registro de usuarios * Administración de recursos humanos * Compra y venta de productos * Inventario * Contabilidad * Rutas de distribución * Capacidad de conectarse con fuentes externas para ampliar el catálogo de productos disponibles. ## Organización del equipo Para solucionar este problema, se utilizará un enfoque de desarrollo ágil, como la metodología Scrum. Esto permitirá que el proyecto sea dividido en pequeñas tareas manejables, y que el equipo de desarrollo pueda trabajar de manera iterativa e incremental para construir el software. Se debe establecer un equipo de desarrollo de software, que esté compuesto por profesionales con experiencia en desarrollo de software y conocimientos específicos en las áreas necesarias para el proyecto, como programación, diseño de bases de datos y seguridad informática. Una vez establecidos los requerimientos, se procederá a planificar el proyecto y dividirlo en iteraciones o "sprints" cortos, que durarán entre una o dos semanas. En cada sprint, se trabajarán en tareas específicas del proyecto, y el equipo de desarrollo se reunirá regularmente para revisar el progreso y hacer ajustes en el plan de ser necesario. En resumen, para solucionar la problemática de desarrollo de software para gestión de actividades empresariales, se utilizará la metodología Scrum para trabajar de manera ágil y dividir el proyecto en pequeñas tareas manejables. Es importante definir claramente los requerimientos y establecer criterios de aceptación y pruebas, mantener una comunicación fluida con el cliente y las fuentes externas, y realizar reuniones regulares de seguimiento y ajuste del plan. ## Arquitectura de servicios En lugar de desarrollar una aplicación monolítica, se optará por una arquitectura basada en microservicios, donde cada funcionalidad se desarrollará y se implementará como un servicio independiente y escalable. Este enfoque permitirá una mayor flexibilidad en la gestión de los recursos y una mayor capacidad de respuesta a los cambios en las necesidades del negocio. Además, la arquitectura en la nube permitirá una mayor escalabilidad y una mejor gestión de los recursos, ya que se podrá implementar los servicios en múltiples instancias en la nube, lo que garantizará la disponibilidad y el rendimiento de la aplicación. Otra ventaja de la arquitectura en la nube es la facilidad para conectarse con fuentes externas, ya que se pueden utilizar herramientas de orquestación de servicios como Kubernetes. La solución propuesta para la gestión de actividades empresariales podría basarse en una arquitectura basada en microservicios y arquitectura en la nube, lo que proporcionaría una mayor escalabilidad, flexibilidad y capacidad de respuesta a las necesidades del negocio. # Microservicios ## 1. Módulo de Usuarios <table> <thead> <tr> <th>Id: 1.1</th> <th>Nombre: Registro de usuarios</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> alta</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Como cliente de la empresa deseo crear un usuario en la plataforma en línea que contenga mis datos personales de manera segura. </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Usuarios</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> El objetivo de este microservicio es crear un nuevo registro en la base de datos correspondiente a los usuarios. Los datos que se guardan en la base de datos son: nombre completo, correo electrónico, fecha de nacimiento, contraseña, dirección. Se debe validar que cada uno de estos datos tenga el formato correcto. Se debe validar que la persona sea mayor de edad. Se deben recibir una contraseña y una confirmación para validar que el usuario no se equivoque al ingresar. Además, la contraseña debe estar encriptada y así se debe guardar en la base de datos. El usuario debe recibir un correo electrónico de confirmación y acceder al mismo antes de estar autorizado. <br><br> <b>Ruta:</b> /user/<br> <b>Método:</b> POST<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> </tbody> </table> <br> <b>Body:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>firstname</td> <td>string</td> <td>Nombres del usuario</td> </tr> <tr> <td>lastname</td> <td>string</td> <td>Apellidos del usuario.</td> </tr> <tr> <td>email</td> <td>string</td> <td>Correo electrónico del usuario.</td> </tr> <tr> <td>password</td> <td>string</td> <td>Contraseña ingresara por el usuario.</td> </tr> <tr> <td>password_confirm</td> <td>string</td> <td>Confirmación de la contraseña del usuario, debe ser la misma que password. </td> </tr> <tr> <td>address</td> <td>string</td> <td>Dirección ingresada por el usuario.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 201 <br> <b>Salida:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>id_user</td> <td>int</td> <td>Id del usuario recien creado. </td> </tr> </tbody> </table> <br> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>400</td> <td>Datos con formato invalido dentro de la petición.</td> </tr> </tbody> </table> <b>Body salida:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>msg</td> <td>string</td> <td>Mensaje con información del error.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre> { "firstname": "Erick", "lastname": "Villatoro", "email": "erickvilla@outlook.com", "password": "saldkfa!FDSAF13241", "password_confirm": "saldkfa!FDSAF13241", "phone": "41122376", "address": "32 av. 12-23 residenciales Hermano Pedro z. 2 Guatemala" } </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { “id_user”: 123 } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 400, “msg”: “Correo electrónico no valido. ” } </pre> </td> </tr> </tbody> </table> <table> <thead> <tr> <th>Id: 1.2</th> <th>Nombre: Desactivación de un usuario</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> baja</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Como administrador deseo eliminar un usuario lógicamente de la base de datos. </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Usuarios</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> El objetivo de este microservicio es eliminar un usuario de la base de datos lógicamente. Para ello se debe contar con un usuario con permisos de administrador, válido por medio del token. <br><br> <b>Ruta:</b> /user/:id_user<br> <b>Método:</b> DELETE<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> <tr> <td>Authorization</td> <td>header</td> <td>Bearer<token></td> </tr> </tbody> </table> <br> <b>Parámetros:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>id_user</td> <td>int</td> <td>Id del usuario que se desea eliminar</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 204 <br> <b>Salida:</b> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>400</td> <td>Id del usuario no valido.</td> </tr> <tr> <td>401</td> <td>Usted no cuenta con los permisos necesarios para realizar esta operación.</td> </tr> <tr> <td>404</td> <td>Usuario no encontrado.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre>http://localhost/user/123 </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { “id_user”: 123 } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 400, “msg”: “Id usuario invalido.” } </pre> <pre> { “status”: 401, “msg”: “Usted no cuenta con los permisos necesarios para realizar esta operación.” } </pre> <pre> { “status”: 404, “msg”: “Usuario {123} no encontrado.” } </pre> </td> </tr> </tbody> </table> <table> <thead> <tr> <th>Id: 1.3</th> <th>Nombre: obtener información de usuario</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> alta</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Como usuario deseo que se muestre la información de mi perfil cuando ingrese a la plataforma. </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Usuarios</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> El objetivo de este microservicio es obtener la información de un registro de la base de datos por medio del identificador de ese usuario. Se debe recibir un token válido y verificarlo y por medio de este consultar a la base de datos se deben retornar los nombres, los apellidos y el correo electrónico. <br><br> <b>Ruta:</b> /user/<br> <b>Método:</b> GET<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> <tr> <td>Authorization</td> <td>header</td> <td>Bearer<token></td> </tr> </tbody> </table> <br> <b>Parámetros de token:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>id_user</td> <td>int</td> <td>Id del usuario que desea obtener su información.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 200 <br> <b>Salida:</b> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>401</td> <td>Token no valido.</td> </tr> <tr> <td>404</td> <td>Usuario no encontrado.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre> { "id_user":123 } </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { "firstname": "Erick", "lastname": "Villatoro", "email": "erickvilla@outlook.com", "phone": "41122376", "address": "32 av. 12-23 residenciales Hermano Pedro z. 2 Guatemala" } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 401, “msg”: “Token inválido.” } </pre> <pre> { “status”: 404, “msg”: “Usuario {123} no encontrado.” } </pre> </td> </tr> </tbody> </table> <table> <thead> <tr> <th>Id: 1.4</th> <th>Nombre: obtener varios usuarios</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> alta</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Como usuario deseo que se muestre la información de mi perfil cuando ingrese a la plataforma. </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Usuarios</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> El objetivo de este microservicio es obtener la información de un registro de la base de datos por medio del identificador de ese usuario. Se debe recibir un token válido y verificarlo y por medio de este consultar a la base de datos se deben retornar los nombres, los apellidos y el correo electrónico. <br><br> <b>Ruta:</b> /user/<br> <b>Método:</b> GET<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> <tr> <td>Authorization</td> <td>header</td> <td>Bearer<token></td> </tr> </tbody> </table> <br> <b>Parámetros de token:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>id_user</td> <td>int</td> <td>Id del usuario que desea obtener su información.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 200 <br> <b>Salida:</b><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>firstname</td> <td>string</td> <td>Nombres del usuario</td> </tr> <tr> <td>lastname</td> <td>string</td> <td>Apellidos del usuario.</td> </tr> <tr> <td>email</td> <td>string</td> <td>Correo electrónico del usuario.</td> </tr> <tr> <td>address</td> <td>string</td> <td>Dirección ingresada por el usuario.</td> </tr> <tr> <td>phone</td> <td>string</td> <td>Telefono del usuario.</td> </tr> </tbody> </table> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>401</td> <td>Token no valido.</td> </tr> <tr> <td>404</td> <td>Usuario no encontrado.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre> { "id_user":123 } </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { "firstname": "Erick", "lastname": "Villatoro", "email": "erickvilla@outlook.com", "phone": "41122376", "address": "32 av. 12-23 residenciales Hermano Pedro z. 2 Guatemala" } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 401, “msg”: “Token inválido.” } </pre> <pre> { “status”: 404, “msg”: “Usuario {123} no encontrado.” } </pre> </td> </tr> </tbody> </table> <table> <thead> <tr> <th>Id: 1.5</th> <th>Nombre: Log In</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> alta</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Como usuario deseo iniciar sesión en la plataforma con mi usuario o correo y la contraseña que registré. </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Usuarios</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> El objetivo de este microservicio es para iniciar sesión dentro de la plataforma. Se debe validar que la contraseña sea correcta y corresponda con la que se tiene guardada en la base de datos. Cuando se haya autenticado al usuario se debe generar un json web token con el id del usuario para que se pueda mantener la sesión iniciada. <br><br> <b>Ruta:</b> /user/auth/<br> <b>Método:</b> POST<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> </tbody> </table> <br> <b>Body</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>email</td> <td>string</td> <td>Correo del usuario.</td> <tr> <td>password</td> <td>string</td> <td>Contraseña del usuario.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 200 <br> <b>Salida:</b><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>jwt</td> <td>string</td> <td>Json Web Token con id_usuario.</td> <tr> </tbody> </table> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>401</td> <td>Credenciales incorrectas.</td> </tr> <tr> <td>404</td> <td>Usuario no encontrado.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre> { "email":evillatoro@outlook.com, "password": asdfawe1123 } </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZF91c2VyIjoiMTIzIn0.agKIYJMIcN37jfUeuWOWA1-D7Gt_mEwNLfrmgZmub7Y" } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 401, “msg”: “Credenciales incorrectas.” } </pre> <pre>{ “status”: 404, “msg”: “Usuario {123} no encontrado.” } </pre> </td> </tr> </tbody> </table> ## 2. Contabilidad ## 3. Inventario ## 4. Nomina <table> <thead> <tr> <th>Id: 4.1</th> <th>Nombre: Registro de empleados</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> alta</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Como empleado de la empresa deseo crear un usuario en la plataforma en línea que contenga mis datos personales de manera segura. </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Nomina</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> El objetivo de este microservicio es crear un nuevo registro en la base de datos correspondiente a los empleados. Los datos que se guardan en la base de datos son: nombre completo, correo electrónico, fecha de nacimiento, contraseña. Se debe validar que cada uno de estos datos tenga el formato correcto. Se deben recibir una contraseña y una confirmación para validar que el usuario no se equivoque al ingresar. Además, la contraseña debe estar encriptada y así se debe guardar en la base de datos. El empleado debe recibir un correo electrónico de confirmación y acceder al mismo antes de estar autorizado. <br><br> <b>Ruta:</b> /employee/<br> <b>Método:</b> POST<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> </tbody> </table> <br> <b>Body:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>firstname</td> <td>string</td> <td>Nombres del usuario</td> </tr> <tr> <td>lastname</td> <td>string</td> <td>Apellidos del usuario.</td> </tr> <tr> <td>email</td> <td>string</td> <td>Correo electrónico del usuario.</td> </tr> <tr> <td>password</td> <td>string</td> <td>Contraseña ingresara por el usuario.</td> </tr> <tr> <td>password_confirm</td> <td>string</td> <td>Confirmación de la contraseña del usuario, debe ser la misma que password. </td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 201 <br> <b>Salida:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>id_employee</td> <td>int</td> <td>Id del empleado recien creado. </td> </tr> </tbody> </table> <br> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>400</td> <td>Datos con formato invalido dentro de la petición.</td> </tr> </tbody> </table> <b>Body salida:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>msg</td> <td>string</td> <td>Mensaje con información del error.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre> { "firstname": "Erick", "lastname": "Villatoro", "email": "erickvilla@outlook.com", "password": "saldkfa!FDSAF13241", "password_confirm": "saldkfa!FDSAF13241" } </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { “id_employee”: 123 } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 400, “msg”: “Correo electrónico no valido. ” } </pre> </td> </tr> </tbody> </table> <table> <thead> <tr> <th>Id: 4.2</th> <th>Nombre: Desactivación de un empleado</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> baja</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Como administrador deseo eliminar un empleado lógicamente de la base de datos. </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Empleados</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> El objetivo de este microservicio es eliminar un empleado de la base de datos lógicamente. Para ello se debe contar con un usuario con permisos de administrador, válido por medio del token. <br><br> <b>Ruta:</b> /employee/:id_employee<br> <b>Método:</b> DELETE<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> <tr> <td>Authorization</td> <td>header</td> <td>Bearer<token></td> </tr> </tbody> </table> <br> <b>Parámetros:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>id_employee</td> <td>int</td> <td>Id del empleado que se desea eliminar</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 204 <br> <b>Salida:</b><br> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>400</td> <td>Id del empleado es inválido.</td> </tr> <tr> <td>401</td> <td>Usted no cuenta con los permisos necesarios para realizar esta operación.</td> </tr> <tr> <td>404</td> <td>Empleado no encontrado.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre>http://localhost/employee/123 </pre><br> <br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 400, “msg”: “Id empleado invalido.” } </pre> <pre> { “status”: 401, “msg”: “Usted no cuenta con los permisos necesarios para realizar esta operación.” } </pre> <pre> { “status”: 404, “msg”: “Empleado {123} no encontrado.” } </pre> </td> </tr> </tbody> </table> <table> <thead> <tr> <th>Id: 4.3</th> <th>Nombre: obtener varios empleados</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> media</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br>Como usuario administrador deseo que se muestre la información de varios empleados. </td> </tr> <tr> <td><b>Estimado:</b> pendiente por grupo</td> </tr> <tr> <td><b>Módulo:</b> Empleados</td> </tr> <tr> <td colspan="2"> <b>Criterios de Aceptación:</b><br> El objetivo de este microservicio es obtener la información de múltiples registros de la base de datos por medio consultas que limiten la búsqueda. Se debe recibir un token válido y verificarlo. <br><br> <b>Ruta:</b> /employee/ <b>Método:</b> GET<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> <tr> <td>Authorization</td> <td>header</td> <td>Bearer<token></td> </tr> </tbody> </table> <br> <b>Parámetros de token:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>id_user</td> <td>int</td> <td>Id del administrador que desea obtener la información.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 200 <br> <b>Salida:</b><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>employees</td> <td>Array</td> <td>Arreglo de empleados con la informacion de cada uno. </td> </tr> </tbody> </table> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>401</td> <td>Token no valido.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { "users": [ { "firstname": "Erick", "lastname": "Villatoro", "email": "erickvilla@outlook.com", "username": "ErickV0212", "birth_day": "15/08/1997", "phone": "41122376" }, { "firstname": "Juan", "lastname": "Alvarado", "email": "juana@outlook.com", "username": "JuanA213", "birth_day": "15/08/1997", "phone": "24124280" } ] } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { “status”: 401, “msg”: “Token inválido.” } </pre> </td> </tr> </tbody> </table> ## 5. Shipping ## 6. Ventas <table> <thead> <tr> <th>Id:6.1 </th> <th> Registrar Venta</th> </tr> </thead> <tbody> <tr> <td><b>Prioridad:</b> alta</td> <td rowspan="3"><b>HISTORIA DE USUARIO</b><br> Como usuario de la plataforma quiero tener la capacidad de registrar una venta de cualquier producto , validando su existencia teniendo también la capacidad de poder ingresar el usuario que esta comprando el producto por medio de su correo electronico. </td> </tr> <tr> <td><b>Estimado:</b> 4h</td> </tr> <tr> <td><b>Módulo:</b> Ventas</td> </tr> <tr> <td colspan="2"><b>Criterios de Aceptación:</b><br>Se espera que se pueda Registar la venta de cualquier producto, con todas las restricciones planteadas como lo són: Que el usuario exista, que el producto tenga disponibilidad y que el pago sea realizado de manera Exitosa. <br><br><b>Ruta:</b> /Ventas/RegistrarVenta<br><b>Método:</b> POST<br> </td> </tr> <tr> <td colspan="2"><b>Formato de entrada:</b> JSON <br> <b>Header:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Content-type</td> <td>header</td> <td>application/json</td> </tr> <tr> <td>Authorization</td> <td>header</td> <td>Bearer&lt;token&gt;</td> </tr> </tbody> </table> <br> <b>Body:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>Correo_Cliente</td> <td>String</td> <td>Correo del usuario que al </td> </tr> <tr> <td>monto</td> <td>int</td> <td> Monto de la transacción</td> </tr> <tr> <td>id_usuario</td> <td>int</td> <td>identificador unico del empleado que esta registrando la compra </td> </tr> <tr> <td>Metodo de pago</td> <td>String</td> <td>Método de pago utilizado para cancelar la transación </td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Formato de salida:</b> JSON <br> <b>Código de respuesta exitosa: </b>HTTP 200 <br> <b>Salida:</b> <br><br> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>status</td> <td>int</td> <td>El código 200 de respuesta exitosa.</td> </tr> <tr> <td>msg</td> <td>string</td> <td>La venta fue realizada exitosamente.</td> </tr> </tbody> </table> <br> <b>Código de respuesta fallida</b> <table> <thead> <tr> <th>Código</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>400</td> <td>Datos con formato invalido dentro de la petición.</td> </tr> <tr> <td>401</td> <td>Credenciales incorrectas dentro del token.</td> </tr> <tr> <td>404</td> <td>indica que el servidor no pudo encontrar el recurso solicitado</td> </tr> </tbody> </table> <b>Body salida:</b> <table> <thead> <tr> <th>Atributo</th> <th>Tipo</th> <th>Descripción</th> </tr> </thead> <tbody> <tr> <td>status</td> <td>int</td> <td>El código de respuesta fallida. </td> </tr> <tr> <td>msg</td> <td>string</td> <td>Mensaje con información del error.</td> </tr> </tbody> </table> </td> </tr> <tr> <td colspan="2"> <b>Ejemplos de parámetros de entrada: </b> <pre> { "Nombre Empleado": "jaudneigoalvaradp@gmail.com", "monto": 2500 "id_usuario":22 "Metodo de pago":"Efectivo" } </pre><br> <b>Ejemplos de parámetros de salida exitosa: </b> <pre> { "status": 200, "msg" : "Venta registrada exitosamente" } </pre><br> <b>Ejemplos de parámetros de salida fallida: </b> <br> <pre> { "status": 400, "msg": "Error en el registro de la venta" } </pre> <pre> { "status": 401, "msg": "Token no válido" }</pre> </td> </tr> </tbody> </table> # Bitácora de tareas La gestión de tareas se llevará por medio del software de gestión de proyectos Jira, agrupando las tareas en seis épicas: 1. Documentación 2. GCP Configuración 3. Pipelines 4. Database 5. Frontend 6. Service Las tareas que se mensionan a continuación están sujetas a cambios con respecto a su tiempo, prioridad y dificultad según se avance en el proyecto. Toda esta bitácora se estará llevando en el siguiente link de igual forma: [Jira - Backlog](https://proyecto-grupo10ayd2.atlassian.net/jira/software/projects/SAG2/boards/2/backlog) ### Documentación | Tarea | Encargado | Tiempo aproximado (Horas) | Prioridad (Alta, media, alta) | Dificultad (1, 2, 3, 5, 8, 13, ...) | | ---------------------------------------------------------------- | ---------------------------- | ------------------------- | ----------------------------- | ----------------------------------- | | Reunión de grupos para la definición de los contratos | Juan Antonio Solares Samayoa | 3 | Alta | 3 | | Creación de contratos del servicio de usuario | Erick José André Villatoro Revolorio | 2 | Media | 5 | | Creación de contratos del servicio de contabilidad | Juan Antonio Solares Samayoa | 2 | Media | 3 | | Creación de contratos del servicio de inventario | Juan Antonio Solares Samayoa |2 | Media | 3 | | Creación de contratos del servicio de nómina | Erick José André Villatoro Revolorio | 1 | Media | 5 | | Creación de contratos del servicio de shipping | Christofer William Borrayo López | 1 | Media | 3 | | Creación de contratos del servicio de ventas | Juan Diego Alvarado Salguero | 1 | Media | 5 | | Diagrama de actividades de tres servicios | Juan Antonio Solares Samayoa | 5 | Media | 5 | | Descripción de la seguridad de la aplicación | Christofer William Borrayo López | 4 | Media | 3 | | Documentación de los pipelines. | Christofer William Borrayo López | 8 | Media | 5 | | Análisis y solución de la problemática propuesta. | Juan Antonio Solares Samayoa | 3 | Media | 3 | | Bitácora de las tareas. | Christofer William Borrayo López | 4 | Media | 5 | | Metodología de ágil justificada del porqué de su selección con sus respectivas etapas. | Juan Antonio Solares Samayoa | 1| Media | 5 | | Diagrama de arquitectura | Erick José André Villatoro Revolorio | 2 | Alta | 5 | ### GCP Configuración | Tarea | Encargado | Tiempo aproximado (Horas) | Prioridad (Alta, media, alta) | Dificultad (1, 2, 3, 5, 8, 13, ...) | | ---------------------------------------------------------------- | ---------------------------- | ------------------------- | ----------------------------- | ----------------------------------- | | Creación de cuenta en GCP | X | X | X | X | | Configuración de Kubernetes en GCP (GKE) | X | X | X | X | | Configuración de Container Registry (GCR) | X | X | X | X | | Configuración de VM para utilizarla como Runner en Gitlab | X | X | X | X | | Configuración de Compute Engine (GCE) como hosting para webpage | X | X | X | X | | Configuración de Cloud SQL | X | X | X | X | ### Pipelines | Tarea | Encargado | Tiempo aproximado (Horas) | Prioridad (Alta, media, alta) | Dificultad (1, 2, 3, 5, 8, 13, ...) | | ---------------------------------------------------------------- | ---------------------------- | ------------------------- | ----------------------------- | ----------------------------------- | | Implementación de Runner en Gitlab | X | X | X | X | | Implementación de Pipeline de autenticación y autorización de usuarios | X | X | X | X | | Implementación de Pipeline de monitoreo y registro de actividades de usuario | X | X | X | X | | Implementación de Pipeline de gestión de parches y actualizaciónes de seguridad | X | X | X | X | | Implementación de Pipeline de pruebas unitarias | X | X | X | X | | Implementación de Pipeline de construcción | X | X | X | X | | Implementación de Pipeline de deployment | X | X | X | X | ### Bases de datos | Tarea | Encargado | Tiempo aproximado (Horas) | Prioridad (Alta, media, alta) | Dificultad (1, 2, 3, 5, 8, 13, ...) | | ---------------------------------------------------------------- | ---------------------------- | ------------------------- | ----------------------------- | ----------------------------------- | | Creación de ER | X | X | X | X | | Configuración de DBMS | X | X | X | X | | Creación del Script | X | X | X | X | | Deployment del Script en Cloud SQL | X | X | X | X | ### Frontedn | Tarea | Encargado | Tiempo aproximado (Horas) | Prioridad (Alta, media, alta) | Dificultad (1, 2, 3, 5, 8, 13, ...) | | ---------------------------------------------------------------- | ---------------------------- | ------------------------- | ----------------------------- | ----------------------------------- | | Creación de views de usuario | X | X | X | X | | Creación de views de recursos humanos | X | X | X | X | | Creación de views de ventas | X | X | X | X | | Creación de views de compras | X | X | X | X | | Creación de views de inventario | X | X | X | X | | Creación de views de contabilidad | X | X | X | X | | Creación de views de rutas | X | X | X | X | | Creación de la plantilla inicial | X | X | X | X | | Implementación de página de inicio de sesion | X | X | X | X | | Implementación de página para registro de usuario | X | X | X | X | | Implementación de página para agregar tarjeta | X | X | X | X | | Implementación de página principal de recursos humanos | X | X | X | X | | Implementación de módulo para crear y dar de baja a usuarios administrativos | X | X | X | X | | Implementación de módulo para agendar entrevistas para contratación | X | X | X | X | | Implementación de página para visualizar entrevistas para contratación | X | X | X | X | | Implementación de módulo para asignar departamentos al usuario | X | X | X | X | | Implementación de página para mostrar el catálogo de productos | X | X | X | X | | Implementación de página para visualizar el carro de compras | X | X | X | X | | Implementación de página para realizar la compra | X | X | X | X | | Implementación de página para mostrar el catálogo de productos de otra empresa | X | X | X | X | | Implementación de página para visualizar el carro de compras de los productos de otra empresaX | X | X | X | X | | Implementación de página para realizar la compra de productos de otra empresa | X | X | X | X | | Implementación de módulo para visualizar las compras a efectuar | X | X | X | X | | Implementación de módulo para visualizar las ventas a efectuar | X | X | X | X | | Implementación de módulo de inventario | X | X | X | X | | Implementación de módulo de contabilidad | X | X | X | X | | Implementación de módulo de shipping | X | X | X | X | ### Services | Tarea | Encargado | Tiempo aproximado (Horas) | Prioridad (Alta, media, alta) | Dificultad (1, 2, 3, 5, 8, 13, ...) | | ---------------------------------------------------------------- | ---------------------------- | ------------------------- | ----------------------------- | ----------------------------------- | | Implementación de servicio de usuarios | X | X | X | X | | Creación de pruebas unitarias de servicio de usuarios | X | X | X | X | | Implementación de servicio de contabilidad | X | X | X | X | | Creación de pruebas unitarias de servicio de contabilidad | X | X | X | X | | Implementación de servicio de inventario | X | X | X | X | | Creación de pruebas unitarias de servicio de inventario | X | X | X | X | | Implementación de servicio de nomina | X | X | X | X | | Creación de pruebas unitarias de servicio de nomina | X | X | X | X | | Implementación de servicio de shipping | X | X | X | X | | Creación de pruebas unitarias de servicio de shipping | X | X | X | X | | Implementación de servicio de ventas | X | X | X | X | | Creación de pruebas unitarias de servicio de ventas | X | X | X | X | # Metodología ágil y su justificación La metodología a utilizar durante el desarrollo de este proyecto será Scrum que es un marco de trabajo de adaptación iterativa e incremental, diseñado para obtener resultados dentro de un proyecto de manera rápida. Las ventajas por los cuales la metodología Scrum será utilizada con las siguientes: **Transparencia**: Se fomenta la transparencia entre miembros del equipo, lo que significa que todos los miembros del equipo deben tener una comprensión clara de lo que se está haciendo, se debe hacer y va a hacerse, para lograr el objetivo de reducir la cantidad de errores. **Flexibilidad**: Scrum aporta un ritmo de trabajo sostenible , siendo capaz de poder adaptarse a cualquier cambio de manera inmediata. **Entrega temprana y continua**: El enfoque de esta metología se centra en entregar un producto funcional lo más antes posible para que el equipo pueda recibir retroalimentación de forma temprana e ir ajustando el enfoque para el producto. **Mejor colaboración y comunicación**: Scrum busca una mejor colaboración y la comunicación de forma constante entre los miembros del equipo. **Reducción de riesgos**: Debido a que se trabajan en ciclos de corta duración, Scrum ayuda a reducir los riesgos y permite que los equipos respondan de forma rápida a cauqluier problema que pueda surgir. Una desventaja es que quienes utilicen esta metodología es se debe tener una alta formación en el tema, debido que al momento de querer implementar esta metodología requiere una exhaustiva definición de las tareas a realizar. # Diagrama de la arquitectura <!-- ![Diagrama de arquitectura](./assets/Diagrama%20de%20arquitectura/arquitectura.png) --> ![](https://i.imgur.com/Mcp1ffu.png)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully