Coder Social home page Coder Social logo

gql_api's People

Contributors

benjvvp avatar fabianhtml avatar fforres avatar hvergara avatar joseglego avatar panchocorderos avatar textc0de avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gql_api's Issues

[IMPROVEMENT] — Mover sendTransactionalHTMLEmail a su propio RPC Service.

Workers tienen que ser lo mas pequeños posible. Pero con la implementación actual, todos los correos están incluidos en el worker principal.

Esto implica que cada instancia del worker principal carga en memoria información referente a correos que quizás nunca enviará en su ciclo de vida. (React, archivos en TSX, tailwind implementation, rendering, etc).

Por lo mismo, deberíamos tener un worker/servicio especializado para el envío de correos, el problema radica en lo complejo que es mantener multiples workers interactuando el uno con otro.

Para solucionar estos problemas, podemos usar RPC's nativos en workers que recientemente Cloudflare implementó.

https://blog.cloudflare.com/javascript-native-rpc

[FEAT] - Crear template de correos

  • Para confirmación de tickets comprados
  • Para confirmación de tickets reservados (cuando son gratis)
  • De recepción para un nuevo usuario

Posteriormente:

  • Como asistente: Cuando un evento se edita.
  • Como asistente: Cuando pediste tu ticket pero estás en espera que te acepten
  • Como asistente: Cuando te aceptan para un evento
  • Como asistente: Cuando quedan X días para el evento
  • Como asistente: Cuando el admin mandó un mensaje a tod@s en el evento.
  • Como organizador Cuando te llega un request de ticket (para que tengas que aceptarlo)

Query — Tickets por Tipo

Deberiamos poder traernos para cada Evento la cantidad de userTickets filtrados por diferentes cosas.

Esto a modo de que los admins puedan filtrar por tipo de ticket, y buscar usuarios mas facil.

Por ejemplo:

  • Tickets activos / cancelados
  • Tickets pagados / no-pagados
  • Tickets aprovados / por approvar.
  • Tickets redimidos / no-redimidos.

Permisos:

  • Admins y colaboradores de una comunidad.
  • Superadmins

[BUG] - Query para `community { users }` no esta retornando los usuarios admins.

Cuando se hace una query como esta:

query comunidadesUsuariosYEventos {
  communities {
    id
    name
    status
    users {
      id
      username
      lastName
      name
      bio
    }
    events {
      id
      name
      address
      description
      startDateTime
      endDateTime
    }
  }
}

Los valores retornados se ven algo así

{
  "data": {
    "communities": [
      {
        "id": "ad398d4b-e0a8-49d5-a3f4-f111451a6757",
        "name": "",
        "status": "inactive",
        "users": [],
        "events": [
          {
            "id": "70f6acdd-304b-4cf2-bbaf-dad4e195824f",
            "name": "Meetup De Miedo — 3",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          },
          {
            "id": "0c9843fe-ac7a-4a1a-8618-f53cf0fb8cba",
            "name": "Meetup De Miedo — 2",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          },
          {
            "id": "8dc704b6-18fe-4cbc-af03-bd2f34fc39ed",
            "name": "Meetup De Miedo!",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          }
        ]
      },
      {
        "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f",
        "name": "JavaScript Chile",
        "status": "inactive",
        "users": [],
        "events": [
          {
            "id": "70f6acdd-304b-4cf2-bbaf-dad4e195824f",
            "name": "Meetup De Miedo — 3",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          },
          {
            "id": "0c9843fe-ac7a-4a1a-8618-f53cf0fb8cba",
            "name": "Meetup De Miedo — 2",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          },
          {
            "id": "8dc704b6-18fe-4cbc-af03-bd2f34fc39ed",
            "name": "Meetup De Miedo!",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          }
        ]
      }
    ]
  }
}

Esta query debería retornar los usuarios que están en esta comunidad. En el caso de esta query, solo existia un usuario en la BDD, que es el ADMIN de ambas comunidades. Pero el campo users no retorna nada de info.

Mutación de Creación de Comunidades

  • Mutación solo puede ser ejecutada por un SuperAdmin.
  • La mutación debe crear comunidades en estado "inactive"

(Para cambiar una comunidad a estado active, lo hacemos desde la mutación de EditarComunidad)

[BUG] — Es posible crear comunidad con nombre de largo 0

Agregar validaciones para largos de textos, al menos en los nombres de comunidades/eventos, o slugs

Se pueden crear por ejemplo, comunidades con nombre vacío (O con string de largo 0). Deberíamos usar ZOD para validar tamaños mínimos de string.

Mutación — Regalar Ticket

Un usuario puede regalar un userTicket a otro usuario.

Cuando un userTicket se regala a otro usuario, el userTicket queda en estado "pendiente de aceptación".

este userTicket no puede ser redimido hasta que la invitación sea aceptada, rechazada, o retirada.

Permisos:

  • Solo el dueño del ticket puede regalar un ticket.

Mutación — Aprobar UserTicket

Un "TICKET" pueden definir que cuando un userTicket se crea, necesita ser aprobado por un admin, antes de ser "activado".

(Por si sirve de contexto... esto es lo que hacemos en LUMA para algunos eventos de nodeschool por ejemplo)
Necesitamos una mutación que le permita a un admin on superAdmin, el "aceptar" un "userTicket"

Permisos

  • El usuario es admin de la comunidad
  • El usuario es superAdmin

Mutación — Editar TIcket

Para cuando queramos editar un Ticket (No un userTicket).
Si queremos cambiarle por ejemplo, el valor a un ticket.

Permisos:

  • isAdmin
  • isSuperAdmin

Mutación —  Update datos de usuario

El usuario tiene que poder updatear sus datos de usuario.

Por ahora, deberiamos permitir updatear:

  • name
  • lastName
  • bio
  • username

Permisos

  • Solo puede updatear un usuario, el usuario actual. Onda el que hace la call.

Mutación — Aceptar Regalo

Un usuario puede regalar un userTicket a otro usuario.
Para asignarlo a un usuario nuevo tiene que ser aceptado por el usuario nuevo.

Cuando un userTicket se regala a otro usuario, el userTicket queda en estado "pendiente de aceptación".

Cuando el userTicket se acepta, se cambia el usuario asignado al userTicket por el usuario que aceptó el regalo.

PS: userTicket no puede ser redimido hasta que la invitación sea aceptada, rechazada, o retirada.

Permisos:

Solo el receptor del regalo puede aceptarlo

Mutación de Edición de Comunidades

Parecido a #74


  • Mutación solo puede ser ejecutada por un SuperAdmin. (Por ahora, cuando asignemos un Admin a la comunidad, derepente deberíamos permitirles updatear solo cierta data)
  • Esta mutación permite cambiar el community.status (active o inactive)

[FEAT] - Parametrizar la URL de retorno post pago

Esta URL esta hardcodeada

success_url: `http://localhost:3000?session_id={CHECKOUT_SESSION_ID}&paymentId=${purchaseOrderId}`,

Necesitamos parametrizarla.
Por ahora/Inicialmente, lo haremos por environment, una variable de entorno en produccion/staging/dev/local

Posteriormente, esto debería (O podría) ser definido por organización. Onda si Comunidad A, quiere definir su propia URL de respuesta distinto de Comunidad B, por ejemplo.

Aunque con un default apuntando a una URL por defecto.

Mutación — Cancelar Regalo

Un usuario puede regalar un userTicket a otro usuario.
Tanto el usuairo nuevo como el que regaló el ticket puede cancelar el regalo.

De ser así, el userTicket vuelve a su estado inicial.

PS: userTicket no puede ser redimido hasta que la invitación sea aceptada, rechazada, o retirada.

Permisos:

  • Receptor y "Regalador" puede aceptar.
  • Tambien superAdmin

Mutación — Crear User Ticket

Un userTicket es la instancia de un ticket. Es la entrada de un usuario a un evento, la entidad que realmente se va a validar/quemar cuando el usuario atienda el evento.
Un userTicket esta a asociado a un "TICKET" .


  • Esta mutación tiene que intentar crear un "userTicket"
  • La manera de asociar un "userTicket" a un TICKET es mediante la tabla user_tickets.
  • Un TICKET esta asociado a un evento
    • (PS: Un evento esta asociado a al menos una comunidad)
  • La mutación debe recibir un TicketID además de los valores del rsvp.

Permisos/validaciones

  • El usuario existe.
  • El evento esta activo.
  • El ticket esta activo.

TODO:

  • Una persona puede reservar tickets gratis.

Extras

  • Hay un límite de tickets por persona.
  • Una persona puede reservar tickets pagados. (AKA, flujo de compra)
  • Idempotency key

[FEAT] — Sincronizar Orden de Compra con procesador de pagos

Cuando se compran tickets, el usuario no esta en nuestro dominio, y (posblemente) es redireccionado a una URL que nosotros definamos.

El problema está en que no tenemos como saber directamente, si la orden de compra fue correctamente pagada.
Para solucionarlo tenemos 3 maneras:

  • Que la URL la que se redireccione al usuario, se le pase un parámetro id_orden_compra con en que podamos llamar a una mutación para sincronizar datos.
  • Habilitar un webhook para que el procesador de pagos nos avise de pagos exitosos/fallidos
  • Setear una cola donde los jobs sean para sincronizar la información con Mercadopago.

Hay tradeoffs en todos los casos, el approach es tener una función agnóstica que reciba un ID de orden de compra y sincronice todo, e implementar al largo plazo los 3 flujos, con el order: Mutación, WebHook, Queue System.

Para el tercero podemos usar https://developers.cloudflare.com/queues/

npm run generate isn't working

Error en el path del comando generate, se arregla eliminando el src del path
"generate": "tsx ./src/generated/generate.ts && graphql-codegen --config codegen.ts"

Neon DB y transacciones

¿Cual es el problema?

Al intentar crear un evento obtengo un mensaje de error informando que Neon no soporta transacciones.

Screenshot 2024-01-04 at 18-03-27 JSChileORG GraphiQL

¿Cual es una posible solución?

Una búsqueda rápida del problema me llevó a esta discusión: https://community.neon.tech/t/how-do-i-handle-transactions/1067

El problema entonces se encontraría aquí:

import { neon, neonConfig } from "@neondatabase/serverless";
import { NeonHttpDatabase, drizzle } from "drizzle-orm/neon-http";
import * as schema from "./schema";
neonConfig.fetchConnectionCache = true;
export type ORM_TYPE = NeonHttpDatabase<typeof schema>;
let db: ORM_TYPE | null = null;
export const getDb = ({ neonUrl }: { neonUrl: string }) => {
if (!db) {
const client = neon(neonUrl);
db = drizzle(client, {
schema: { ...schema },
logger: {
logQuery(query, params) {
// eslint-disable-next-line no-console
console.log(query, params);
},
},
});
}
return db;
};

Cambiando la función por esto permite crear el evento sin problemas:

import { Pool, neonConfig } from "@neondatabase/serverless";
import { NeonDatabase, drizzle } from "drizzle-orm/neon-serverless";
import * as schema from "./schema";

neonConfig.fetchConnectionCache = true;

export type ORM_TYPE = NeonDatabase<typeof schema>;
let db: ORM_TYPE | null = null;
export const getDb = ({ neonUrl }: { neonUrl: string }) => {
  if (!db) {
    const pool = new Pool({ connectionString: neonUrl });
    db = drizzle(pool, {
      schema: { ...schema },
      logger: {
        logQuery(query, params) {
          // eslint-disable-next-line no-console
          console.log(query, params);
        },
      },
    });

    return db;
  }

  return db;
};

Screenshot 2024-01-04 at 18-18-46 JSChileORG GraphiQL

[FIX] - Parametrizar la URL de "compra exitosa"

Esta API no esta creada para ser usada en una sola aplicación, por lo que cuando un usuario compre exitosamente sus tickets, deberíamos permitir que cada comunidad pueda decidir a donde redireccionar a sus usuarios post compra.

Moverse de `Resend` a Azure o Cloudflare para el envio de correos

Resend es bkn pero es medio carosi cuando escalemos. Onda 50.000 correos salen 20 USD al mes. (Es caleta la verdad 😆, pero tenemos creditos de azure, que deberiamos usar). Segun mis cálculos. Con nuestros créditos de azure, podriamos mandar 500.000 correos x Mes.

Calcular Métricas de Performance

Esto no es mega importante ahora, pero seria genial cachar cosas como:

  • Una query que DB muy lenta, o que falle constantemente.
  • Cual es el resolver mas lentos? (O cual es su performance en general)

Cuanto tiempo pasamos:

  • Parseando la query
  • Juntando los datos en reolvers
  • Devolviendo la respuesta.

Si tenemos una query lenta. Podemos cachar porque es lenta?

  • Que resolvers son los problematicos?
  • Hay algo generando un N+1??

Mutación — Redimir UserTicket

Para cuando estemos en un evento y tengamos que redimir un ticket.
Básicamente cuando estamos en la entrada y escaneamos el ticket.

Permisos:

  • Voluntarios y admins de una comunidad.
  • isSuperAdmin

MIGRATE to Resend

Problema

Mailchannels anunció EOL para su soporte con Cloudflare.
https://support.mailchannels.com/hc/en-us/articles/26814255454093-End-of-Life-Notice-Cloudflare-Workers

(Seems they suck TBH 😞)
https://community.cloudflare.com/t/this-week-mailchannels-will-enforce-domain-lockdown-on-legacy-workers-users/544874/1

Solucion:

Migrarse a Resend. Free for now, luego 20USD mes.

Otras opciones

podríamos migrarnos a azure, pero la lata de implementación/soporte es mucha.
Sendgrid sale 25 centavos menos al menos 🤷🏼 y es mas lenta la implementación.

Mutación — Cancelar User Ticket

No vamos a realmente eliminar ningún userTicket.
Pero tenemos que poder hacer un Soft-delete de cosas, asi que sería setear el campo deletedAt y el status.

[BUG] Resolver de Eventos: Retorno Incorrecto de Comunidades Asociadas

En el proyecto, se maneja una relación many-to-many entre eventos y comunidades.
Esta relación se evidencia en la siguiente imagen, específicamente en la tabla events_communities:

Sin embargo, el código actual devuelve solo la primera comunidad asociada a cada evento, lo cual parece incoherente con la naturaleza de la relación many-to-many. El fragmento de código que está causando este comportamiento es el siguiente:

community: t.field({
type: CommunityRef,
nullable: true,
resolve: async (root, args, ctx) => {
const community = await ctx.DB.query.communitySchema.findFirst({
with: {
eventsToCommunities: {
where: (etc, { eq }) => eq(etc.eventId, root.id),
},
},
});
if (!community) {
return null;
}
return selectCommunitySchema.parse(community);
},
}),

Además, en algunas consultas, la comunidad devuelta no corresponde a la asociada al evento, similar al problema reportado en el issue #81.

Un ejemplo concreto de este problema se observa en la siguiente query y sus resultados, donde el evento con id 9d38e167-e376-476d-829d-10953675921e está vinculado incorrectamente a la comunidad con id c012d08f-e8e5-40ea-997a-d78bc1de4952:

query events {
  events {
    id
    name
    community {
      id
      name
    }
  }
}

Resultado Incorrecto de Query
Validación de Datos

[BUG] Query por `community { events }` retorna eventos asociados a otras comunidades

La siguiente query.

query comunidadesUsuariosYEventos {
  communities {
    id
    name
    status
    events {
      id
      name
      address
      description
      startDateTime
      endDateTime
    }
  }
}

retorna los siguientes valores:

{
  "data": {
    "communities": [
      {
        "id": "ad398d4b-e0a8-49d5-a3f4-f111451a6757",
        "name": "",
        "status": "inactive",
        "events": [
          {
            "id": "70f6acdd-304b-4cf2-bbaf-dad4e195824f",
            "name": "Meetup De Miedo — 3",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          },
          {
            "id": "0c9843fe-ac7a-4a1a-8618-f53cf0fb8cba",
            "name": "Meetup De Miedo — 2",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          },
          {
            "id": "8dc704b6-18fe-4cbc-af03-bd2f34fc39ed",
            "name": "Meetup De Miedo!",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          }
        ]
      },
      {
        "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f",
        "name": "JavaScript Chile",
        "status": "inactive",
        "events": [
          {
            "id": "70f6acdd-304b-4cf2-bbaf-dad4e195824f",
            "name": "Meetup De Miedo — 3",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          },
          {
            "id": "0c9843fe-ac7a-4a1a-8618-f53cf0fb8cba",
            "name": "Meetup De Miedo — 2",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          },
          {
            "id": "8dc704b6-18fe-4cbc-af03-bd2f34fc39ed",
            "name": "Meetup De Miedo!",
            "address": null,
            "description": "Dummy Meetup de Octubre",
            "startDateTime": "2024-10-18T06:58:39.081Z",
            "endDateTime": null
          }
        ]
      }
    ]
  }
}

Los eventos de una comunidad aparecen en la otra. Lo que quiere decir que no estamos filtrando por comunidad, al obtener los eventos de una comunidad.

Es mas notorio si hacemos la siguiente query, donde nos traemos comindades -> evnetos -> comunidad de cada evento.

query comunidadesUsuariosYEventos {
  communities {
    id
    events {
      id
      community {
        id
      }
    }
  }
}

los resultados son:

{
  "data": {
    "communities": [
      {
        "id": "ad398d4b-e0a8-49d5-a3f4-f111451a6757",
        "events": [
          {
            "id": "70f6acdd-304b-4cf2-bbaf-dad4e195824f",
            "community": {
              "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f"
            }
          },
          {
            "id": "0c9843fe-ac7a-4a1a-8618-f53cf0fb8cba",
            "community": {
              "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f"
            }
          },
          {
            "id": "8dc704b6-18fe-4cbc-af03-bd2f34fc39ed",
            "community": {
              "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f"
            }
          }
        ]
      },
      {
        "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f",
        "events": [
          {
            "id": "70f6acdd-304b-4cf2-bbaf-dad4e195824f",
            "community": {
              "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f"
            }
          },
          {
            "id": "0c9843fe-ac7a-4a1a-8618-f53cf0fb8cba",
            "community": {
              "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f"
            }
          },
          {
            "id": "8dc704b6-18fe-4cbc-af03-bd2f34fc39ed",
            "community": {
              "id": "e1330085-cc7f-4a82-a74d-b84b2d8c760f"
            }
          }
        ]
      }
    ]
  }
}

[FEAT] Soportar Mercadopago

Tenemos que soportar la creación de purchase-orders o de links de pago, a través de MercadoPago, para precios Chilenos.

[FEAT] — Agregar check de expiración de orden de compra

Crear un metodo para revisar si una OC está "no pagada" más allá de su tiempo de expiración (31 minutos).

De ser así, marcarla como cancelada.

Este método se tiene que llamar desde un cron, cada 5 minutos.
Además, se debe llamar al final de la mutación de checkPurchaseOrderStatus

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.